From 6b4cf67add1b36fef02b93054a5db2269e6b76c4 Mon Sep 17 00:00:00 2001 From: HystericalDragon Date: Fri, 17 Jan 2025 11:21:07 +0800 Subject: [PATCH 01/62] Fix endpoints not close --- box.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/box.go b/box.go index 1908f6db..0cbf1b3b 100644 --- a/box.go +++ b/box.go @@ -399,7 +399,7 @@ func (s *Box) Close() error { close(s.done) } err := common.Close( - s.inbound, s.outbound, s.router, s.connection, s.network, + s.inbound, s.outbound, s.endpoint, s.router, s.connection, s.network, ) for _, lifecycleService := range s.services { err = E.Append(err, lifecycleService.Close(), func(err error) error { From 08c1ec4b7e406293ab650112f3354410f8dbe53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Jan 2025 09:39:11 +0800 Subject: [PATCH 02/62] Fix legacy routes --- route/route.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/route/route.go b/route/route.go index ca747462..bb29261c 100644 --- a/route/route.go +++ b/route/route.go @@ -33,7 +33,18 @@ import ( // Deprecated: use RouteConnectionEx instead. func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { - return r.routeConnection(ctx, conn, metadata, nil) + done := make(chan interface{}) + err := r.routeConnection(ctx, conn, metadata, N.OnceClose(func(it error) { + close(done) + })) + if err != nil { + return err + } + select { + case <-done: + case <-r.ctx.Done(): + } + return nil } func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { @@ -141,7 +152,10 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad } func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { - err := r.routePacketConnection(ctx, conn, metadata, nil) + done := make(chan interface{}) + err := r.routePacketConnection(ctx, conn, metadata, N.OnceClose(func(it error) { + close(done) + })) if err != nil { conn.Close() if E.IsClosedOrCanceled(err) { @@ -150,6 +164,10 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m r.logger.ErrorContext(ctx, err) } } + select { + case <-done: + case <-r.ctx.Done(): + } return nil } From eeb37d89f181f323741b9dcfaeb287c593ef176d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 27 Jan 2025 09:24:55 +0800 Subject: [PATCH 03/62] Fix rule-set upgrade command --- cmd/sing-box/cmd_rule_set_upgrade.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/sing-box/cmd_rule_set_upgrade.go b/cmd/sing-box/cmd_rule_set_upgrade.go index e885d849..3d77a1d2 100644 --- a/cmd/sing-box/cmd_rule_set_upgrade.go +++ b/cmd/sing-box/cmd_rule_set_upgrade.go @@ -61,14 +61,15 @@ func upgradeRuleSet(sourcePath string) error { log.Info("already up-to-date") return nil } - plainRuleSet, err := plainRuleSetCompat.Upgrade() + plainRuleSetCompat.Options, err = plainRuleSetCompat.Upgrade() if err != nil { return err } + plainRuleSetCompat.Version = C.RuleSetVersionCurrent buffer := new(bytes.Buffer) encoder := json.NewEncoder(buffer) encoder.SetIndent("", " ") - err = encoder.Encode(plainRuleSet) + err = encoder.Encode(plainRuleSetCompat) if err != nil { return E.Cause(err, "encode config") } From 4807e646092dfadb8eaae23a6eb729cd77e17bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 27 Jan 2025 10:03:59 +0800 Subject: [PATCH 04/62] documentation: Fix typo --- docs/configuration/outbound/wireguard.zh.md | 2 +- docs/configuration/route/rule_action.md | 78 ++++++++++----------- docs/configuration/route/rule_action.zh.md | 78 ++++++++++----------- 3 files changed, 79 insertions(+), 79 deletions(-) diff --git a/docs/configuration/outbound/wireguard.zh.md b/docs/configuration/outbound/wireguard.zh.md index c4e77c24..4597fd9d 100644 --- a/docs/configuration/outbound/wireguard.zh.md +++ b/docs/configuration/outbound/wireguard.zh.md @@ -4,7 +4,7 @@ icon: material/delete-clock !!! failure "已在 sing-box 1.11.0 废弃" - WireGuard 出站已被启用,且将在 sing-box 1.13.0 中被移除,参阅 [迁移指南](/migration/#migrate-wireguard-outbound-to-endpoint)。 + WireGuard 出站已被弃用,且将在 sing-box 1.13.0 中被移除,参阅 [迁移指南](/migration/#migrate-wireguard-outbound-to-endpoint)。 !!! quote "sing-box 1.11.0 中的更改" diff --git a/docs/configuration/route/rule_action.md b/docs/configuration/route/rule_action.md index fae52e85..31256e25 100644 --- a/docs/configuration/route/rule_action.md +++ b/docs/configuration/route/rule_action.md @@ -31,6 +31,45 @@ Tag of target outbound. See `route-options` fields below. +### reject + +```json +{ + "action": "reject", + "method": "default", // default + "no_drop": false +} +``` + +`reject` reject connections + +The specified method is used for reject tun connections if `sniff` action has not been performed yet. + +For non-tun connections and already established connections, will just be closed. + +#### method + +- `default`: Reply with TCP RST for TCP connections, and ICMP port unreachable for UDP packets. +- `drop`: Drop packets. + +#### no_drop + +If not enabled, `method` will be temporarily overwritten to `drop` after 50 triggers in 30s. + +Not available when `method` is set to drop. + +### hijack-dns + +```json +{ + "action": "hijack-dns" +} +``` + +`hijack-dns` hijack DNS requests to the sing-box DNS module. + +## Non-final actions + ### route-options ```json @@ -109,45 +148,6 @@ If no protocol is sniffed, the following ports will be recognized as protocols b | 443 | `quic` | | 3478 | `stun` | -### reject - -```json -{ - "action": "reject", - "method": "default", // default - "no_drop": false -} -``` - -`reject` reject connections - -The specified method is used for reject tun connections if `sniff` action has not been performed yet. - -For non-tun connections and already established connections, will just be closed. - -#### method - -- `default`: Reply with TCP RST for TCP connections, and ICMP port unreachable for UDP packets. -- `drop`: Drop packets. - -#### no_drop - -If not enabled, `method` will be temporarily overwritten to `drop` after 50 triggers in 30s. - -Not available when `method` is set to drop. - -### hijack-dns - -```json -{ - "action": "hijack-dns" -} -``` - -`hijack-dns` hijack DNS requests to the sing-box DNS module. - -## Non-final actions - ### sniff ```json diff --git a/docs/configuration/route/rule_action.zh.md b/docs/configuration/route/rule_action.zh.md index 2f558f4e..544918d4 100644 --- a/docs/configuration/route/rule_action.zh.md +++ b/docs/configuration/route/rule_action.zh.md @@ -27,6 +27,45 @@ icon: material/new-box 参阅下方的 `route-options` 字段。 +### reject + +```json +{ + "action": "reject", + "method": "default", // 默认 + "no_drop": false +} +``` + +`reject` 拒绝连接。 + +如果尚未执行 `sniff` 操作,则将使用指定方法拒绝 tun 连接。 + +对于非 tun 连接和已建立的连接,将直接关闭。 + +#### method + +- `default`: 对于 TCP 连接回复 RST,对于 UDP 包回复 ICMP 端口不可达。 +- `drop`: 丢弃数据包。 + +#### no_drop + +如果未启用,则 30 秒内触发 50 次后,`method` 将被暂时覆盖为 `drop`。 + +当 `method` 设为 `drop` 时不可用。 + +### hijack-dns + +```json +{ + "action": "hijack-dns" +} +``` + +`hijack-dns` 劫持 DNS 请求至 sing-box DNS 模块。 + +## 非最终动作 + ### route-options ```json @@ -107,45 +146,6 @@ UDP 连接超时时间。 | 443 | `quic` | | 3478 | `stun` | -### reject - -```json -{ - "action": "reject", - "method": "default", // 默认 - "no_drop": false -} -``` - -`reject` 拒绝连接。 - -如果尚未执行 `sniff` 操作,则将使用指定方法拒绝 tun 连接。 - -对于非 tun 连接和已建立的连接,将直接关闭。 - -#### method - -- `default`: 对于 TCP 连接回复 RST,对于 UDP 包回复 ICMP 端口不可达。 -- `drop`: 丢弃数据包。 - -#### no_drop - -如果未启用,则 30 秒内触发 50 次后,`method` 将被暂时覆盖为 `drop`。 - -当 `method` 设为 `drop` 时不可用。 - -### hijack-dns - -```json -{ - "action": "hijack-dns" -} -``` - -`hijack-dns` 劫持 DNS 请求至 sing-box DNS 模块。 - -## 非最终动作 - ### sniff ```json From 3923b57abfa6c024c4d2691ed5126a8ffde38044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 27 Jan 2025 10:33:16 +0800 Subject: [PATCH 05/62] release: Update NDK to r28-beta3 --- .github/workflows/build.yml | 10 +++++----- .goreleaser.yaml | 2 +- cmd/internal/build_shared/sdk.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b813a66c..000ac3e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -144,7 +144,7 @@ jobs: ~/go/go1.20.14 key: go120 - name: Setup legacy Go - if: matrix.require_legacy_go == 'true' && steps.cache-legacy-go.outputs.cache-hit != 'true' + if: matrix.require_legacy_go && steps.cache-legacy-go.outputs.cache-hit != 'true' run: |- wget https://dl.google.com/go/go1.20.14.linux-amd64.tar.gz tar -xzf go1.20.14.linux-amd64.tar.gz @@ -159,7 +159,7 @@ jobs: uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro - version: latest + version: 2.5.1 install-only: true - name: Extract signing key run: |- @@ -224,7 +224,7 @@ jobs: id: setup-ndk uses: nttld/setup-ndk@v1 with: - ndk-version: r28-beta2 + ndk-version: r28-beta3 - name: Setup OpenJDK run: |- sudo apt update && sudo apt install -y openjdk-17-jdk-headless @@ -299,7 +299,7 @@ jobs: id: setup-ndk uses: nttld/setup-ndk@v1 with: - ndk-version: r28-beta2 + ndk-version: r28-beta3 - name: Setup OpenJDK run: |- sudo apt update && sudo apt install -y openjdk-17-jdk-headless @@ -548,7 +548,7 @@ jobs: uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro - version: latest + version: 2.5.1 install-only: true - name: Cache ghr uses: actions/cache@v4 diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 62136cfc..9eb02c94 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -52,7 +52,7 @@ builds: env: - CGO_ENABLED=0 - GOROOT={{ .Env.GOPATH }}/go1.20.14 - gobinary: "{{ .Env.GOPATH }}/go1.20.14/bin/go" + tool: "{{ .Env.GOPATH }}/go1.20.14/bin/go" targets: - windows_amd64_v1 - windows_386 diff --git a/cmd/internal/build_shared/sdk.go b/cmd/internal/build_shared/sdk.go index 5dbefa4a..eab95216 100644 --- a/cmd/internal/build_shared/sdk.go +++ b/cmd/internal/build_shared/sdk.go @@ -48,7 +48,7 @@ func FindSDK() { } func findNDK() bool { - const fixedVersion = "28.0.12674087" + const fixedVersion = "28.0.12916984" const versionFile = "source.properties" if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.IsFile(filepath.Join(fixedPath, versionFile)) { androidNDKPath = fixedPath From 9b73222314e32fbe3f797aca4525fc9b0c6166dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 18 Nov 2024 19:00:56 +0800 Subject: [PATCH 06/62] documentation: Bump version --- docs/changelog.md | 228 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 1 deletion(-) diff --git a/docs/changelog.md b/docs/changelog.md index 9a550912..c1ce3194 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,16 +2,242 @@ icon: material/alert-decagram --- +#### 1.11.0-rc.1 + +* Fixes and improvements + ### 1.10.7 * Fixes and improvements +#### 1.11.0-beta.20 + +* Hysteria2 `ignore_client_bandwidth` behavior update **1** +* Fixes and improvements + +**1**: + +When `up_mbps` and `down_mbps` are set, `ignore_client_bandwidth` instead denies clients from using BBR CC. + +See [Hysteria2](/configuration/inbound/hysteria2/#ignore_client_bandwidth). + +#### 1.11.0-beta.17 + +* Add port hopping support for Hysteria2 **1** +* Fixes and improvements + +**1**: + +See [Hysteria2](/configuration/outbound/hysteria2/). + +#### 1.11.0-beta.14 + +* Allow adding route (exclude) address sets to routes **1** +* Fixes and improvements + +**1**: + +When `auto_redirect` is not enabled, directly add `route[_exclude]_address_set` +to tun routes (equivalent to `route[_exclude]_address`). + +Note that it **doesn't work on the Android graphical client** due to +the Android VpnService not being able to handle a large number of routes (DeadSystemException), +but otherwise it works fine on all command line clients and Apple platforms. + +See [route_address_set](/configuration/inbound/tun/#route_address_set) and +[route_exclude_address_set](/configuration/inbound/tun/#route_exclude_address_set). + +#### 1.11.0-beta.12 + +* Add `rule-set merge` command +* Fixes and improvements + +#### 1.11.0-beta.3 + +* Add more masquerade options for hysteria2 **1** +* Fixes and improvements + +**1**: + +See [Hysteria2](/configuration/inbound/hysteria2/#masquerade). + +#### 1.11.0-alpha.25 + +* Update quic-go to v0.48.2 +* Fixes and improvements + +#### 1.11.0-alpha.22 + +* Add UDP timeout route option **1** +* Fixes and improvements + +**1**: + +See [Rule Action](/configuration/route/rule_action/#udp_timeout). + +#### 1.11.0-alpha.20 + +* Add UDP GSO support for WireGuard +* Make GSO adaptive **1** + +**1**: + +For WireGuard outbound and endpoint, GSO will be automatically enabled when available, +see [WireGuard Outbound](/configuration/outbound/wireguard/#gso). + +For TUN, GSO has been removed, +see [Deprecated](/deprecated/#gso-option-in-tun). + +#### 1.11.0-alpha.19 + +* Upgrade WireGuard outbound to endpoint **1** +* Fixes and improvements + +**1**: + +The new WireGuard endpoint combines inbound and outbound capabilities, +and the old outbound will be removed in sing-box 1.13.0. + +See [Endpoint](/configuration/endpoint/), [WireGuard Endpoint](/configuration/endpoint/wireguard/) +and [Migrate WireGuard outbound fields to route options](/migration/#migrate-wireguard-outbound-to-endpoint). + ### 1.10.2 * Add deprecated warnings * Fix proxying websocket connections in HTTP/mixed inbounds * Fixes and improvements +#### 1.11.0-alpha.18 + +* Fixes and improvements + +#### 1.11.0-alpha.16 + +* Add `cache_capacity` DNS option **1** +* Add `override_address` and `override_port` route options **2** +* Fixes and improvements + +**1**: + +See [DNS](/configuration/dns/#cache_capacity). + +**2**: + +See [Rule Action](/configuration/route/#override_address) and +[Migrate destination override fields to route options](/migration/#migrate-destination-override-fields-to-route-options). + +#### 1.11.0-alpha.15 + +* Improve multi network dialing **1** +* Fixes and improvements + +**1**: + +New options allow you to configure the network strategy flexibly. + +See [Dial Fields](/configuration/shared/dial/#network_strategy), +[Rule Action](/configuration/route/rule_action/#network_strategy) +and [Route](/configuration/route/#default_network_strategy). + +#### 1.11.0-alpha.14 + +* Add multi network dialing **1** +* Fixes and improvements + +**1**: + +Similar to Surge's strategy. + +New options allow you to connect using multiple network interfaces, +prefer or only use one type of interface, +and configure a timeout to fallback to other interfaces. + +See [Dial Fields](/configuration/shared/dial/#network_strategy), +[Rule Action](/configuration/route/rule_action/#network_strategy) +and [Route](/configuration/route/#default_network_strategy). + +#### 1.11.0-alpha.13 + +* Fixes and improvements + +#### 1.11.0-alpha.12 + +* Merge route options to route actions **1** +* Add `network_type`, `network_is_expensive` and `network_is_constrainted` rule items **2** +* Fixes and improvements + +**1**: + +Route options in DNS route actions will no longer be considered deprecated, +see [DNS Route Action](/configuration/dns/rule_action/). + +Also, now `udp_disable_domain_unmapping` and `udp_connect` can also be configured in route action, +see [Route Action](/configuration/route/rule_action/). + +**2**: + +When using in graphical clients, new routing rule items allow you to match on +network type (WIFI, cellular, etc.), whether the network is expensive, and whether Low Data Mode is enabled. + +See [Route Rule](/configuration/route/rule/), [DNS Route Rule](/configuration/dns/rule/) +and [Headless Rule](/configuration/rule-set/headless-rule/). + +#### 1.11.0-alpha.9 + +* Improve tun compatibility **1** +* Fixes and improvements + +**1**: + +When `gvisor` tun stack is enabled, even if the request passes routing, +if the outbound connection establishment fails, +the connection still does not need to be established and a TCP RST is replied. + +#### 1.11.0-alpha.7 + +* Introducing rule actions **1** + +**1**: + +New rule actions replace legacy inbound fields and special outbound fields, +and can be used for pre-matching **2**. + +See [Rule](/configuration/route/rule/), +[Rule Action](/configuration/route/rule_action/), +[DNS Rule](/configuration/dns/rule/) and +[DNS Rule Action](/configuration/dns/rule_action/). + +For migration, see +[Migrate legacy special outbounds to rule actions](/migration/#migrate-legacy-special-outbounds-to-rule-actions), +[Migrate legacy inbound fields to rule actions](/migration/#migrate-legacy-inbound-fields-to-rule-actions) +and [Migrate legacy DNS route options to rule actions](/migration/#migrate-legacy-dns-route-options-to-rule-actions). + +**2**: + +Similar to Surge's pre-matching. + +Specifically, new rule actions allow you to reject connections with +TCP RST (for TCP connections) and ICMP port unreachable (for UDP packets) +before connection established to improve tun's compatibility. + +See [Rule Action](/configuration/route/rule_action/). + +#### 1.11.0-alpha.6 + +* Update quic-go to v0.48.1 +* Set gateway for tun correctly +* Fixes and improvements + +#### 1.11.0-alpha.2 + +* Add warnings for usage of deprecated features +* Fixes and improvements + +#### 1.11.0-alpha.1 + +* Update quic-go to v0.48.0 +* Fixes and improvements + ### 1.10.1 * Fixes and improvements @@ -87,7 +313,7 @@ allows you to write headless rules directly without creating a rule-set file. **8**: -With the new access control options, not only can you allow Clash dashboards +With new access control options, not only can you allow Clash dashboards to access the Clash API on your local network, you can also manually limit the websites that can access the API instead of allowing everyone. From e64cf3b7df3a2ead890aabcab1860fd85f8b1924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 27 Jan 2025 13:40:26 +0800 Subject: [PATCH 07/62] Do not set address sets to routes on Apple platforms Network Extension was observed to stop for unknown reasons --- experimental/libbox/config.go | 4 --- experimental/libbox/platform.go | 1 - experimental/libbox/platform/interface.go | 1 - experimental/libbox/service.go | 14 --------- protocol/tun/inbound.go | 38 ++--------------------- 5 files changed, 2 insertions(+), 56 deletions(-) diff --git a/experimental/libbox/config.go b/experimental/libbox/config.go index 6a85c963..159fd8f6 100644 --- a/experimental/libbox/config.go +++ b/experimental/libbox/config.go @@ -66,10 +66,6 @@ func (s *platformInterfaceStub) OpenTun(options *tun.Options, platformOptions op return nil, os.ErrInvalid } -func (s *platformInterfaceStub) UpdateRouteOptions(options *tun.Options, platformInterface option.TunPlatformOptions) error { - return os.ErrInvalid -} - func (s *platformInterfaceStub) UsePlatformDefaultInterfaceMonitor() bool { return true } diff --git a/experimental/libbox/platform.go b/experimental/libbox/platform.go index 2503ea44..d5951cd3 100644 --- a/experimental/libbox/platform.go +++ b/experimental/libbox/platform.go @@ -9,7 +9,6 @@ type PlatformInterface interface { UsePlatformAutoDetectInterfaceControl() bool AutoDetectInterfaceControl(fd int32) error OpenTun(options TunOptions) (int32, error) - UpdateRouteOptions(options TunOptions) error WriteLog(message string) UseProcFS() bool FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error) diff --git a/experimental/libbox/platform/interface.go b/experimental/libbox/platform/interface.go index eda51b48..ef37daea 100644 --- a/experimental/libbox/platform/interface.go +++ b/experimental/libbox/platform/interface.go @@ -13,7 +13,6 @@ type Interface interface { UsePlatformAutoDetectInterfaceControl() bool AutoDetectInterfaceControl(fd int) error OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) - UpdateRouteOptions(options *tun.Options, platformOptions option.TunPlatformOptions) error CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor Interfaces() ([]adapter.NetworkInterface, error) UnderNetworkExtension() bool diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 4906c571..8d42d26e 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -174,20 +174,6 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions return tun.New(*options) } -func (w *platformInterfaceWrapper) UpdateRouteOptions(options *tun.Options, platformOptions option.TunPlatformOptions) error { - if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 { - return E.New("android: unsupported uid options") - } - if len(options.IncludeAndroidUser) > 0 { - return E.New("android: unsupported android_user option") - } - routeRanges, err := options.BuildAutoRouteRanges(true) - if err != nil { - return err - } - return w.iif.UpdateRouteOptions(&tunOptions{options, routeRanges, platformOptions}) -} - func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor { return &platformDefaultInterfaceMonitor{ platformInterfaceWrapper: w, diff --git a/protocol/tun/inbound.go b/protocol/tun/inbound.go index 34a5db2b..3bbe0421 100644 --- a/protocol/tun/inbound.go +++ b/protocol/tun/inbound.go @@ -305,7 +305,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error { if t.tunOptions.Name == "" { t.tunOptions.Name = tun.CalculateInterfaceName("") } - if t.platformInterface == nil || runtime.GOOS != "android" { + if t.platformInterface == nil { t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet) for _, routeRuleSet := range t.routeRuleSet { ipSets := routeRuleSet.ExtractIPSet() @@ -421,41 +421,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error { func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) { t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet) t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet) - if t.autoRedirect != nil { - t.autoRedirect.UpdateRouteAddressSet() - } else { - tunOptions := t.tunOptions - for _, ipSet := range t.routeAddressSet { - for _, prefix := range ipSet.Prefixes() { - if prefix.Addr().Is4() { - tunOptions.Inet4RouteAddress = append(tunOptions.Inet4RouteAddress, prefix) - } else { - tunOptions.Inet6RouteAddress = append(tunOptions.Inet6RouteAddress, prefix) - } - } - } - for _, ipSet := range t.routeExcludeAddressSet { - for _, prefix := range ipSet.Prefixes() { - if prefix.Addr().Is4() { - tunOptions.Inet4RouteExcludeAddress = append(tunOptions.Inet4RouteExcludeAddress, prefix) - } else { - tunOptions.Inet6RouteExcludeAddress = append(tunOptions.Inet6RouteExcludeAddress, prefix) - } - } - } - if t.platformInterface != nil { - err := t.platformInterface.UpdateRouteOptions(&tunOptions, t.platformOptions) - if err != nil { - t.logger.Error("update route addresses: ", err) - } - } else { - err := t.tunIf.UpdateRouteOptions(tunOptions) - if err != nil { - t.logger.Error("update route addresses: ", err) - } - } - t.logger.Info("updated route addresses") - } + t.autoRedirect.UpdateRouteAddressSet() t.routeAddressSet = nil t.routeExcludeAddressSet = nil } From d09d2fb665f1a4aa0cefb1ce0298539867ba487b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 27 Jan 2025 13:22:08 +0800 Subject: [PATCH 08/62] Bump version --- clients/android | 2 +- clients/apple | 2 +- docs/changelog.md | 120 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/clients/android b/clients/android index b17fb6d8..599d8cec 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit b17fb6d8570251ff1d0494d07d77b45f44006607 +Subproject commit 599d8cecacf2ef732b92b3153c08b1b45074661c diff --git a/clients/apple b/clients/apple index 64a4614a..e43e3a3f 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit 64a4614aca01e1e9b8369ab9f542da737b3f7619 +Subproject commit e43e3a3f64886c5ebaa8e41348b4a4e048a0b5b1 diff --git a/docs/changelog.md b/docs/changelog.md index c1ce3194..c37bdf71 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,9 +2,125 @@ icon: material/alert-decagram --- -#### 1.11.0-rc.1 +### 1.11.0 -* Fixes and improvements +Important changes since 1.10: + +* Introducing rule actions **1** +* Improve tun compatibility **3** +* Merge route options to route actions **4** +* Add `network_type`, `network_is_expensive` and `network_is_constrainted` rule items **5** +* Add multi network dialing **6** +* Add `cache_capacity` DNS option **7** +* Add `override_address` and `override_port` route options **8** +* Upgrade WireGuard outbound to endpoint **9** +* Add UDP GSO support for WireGuard +* Make GSO adaptive **10** +* Add UDP timeout route option **11** +* Add more masquerade options for hysteria2 **12** +* Add `rule-set merge` command +* Add port hopping support for Hysteria2 **13** +* Hysteria2 `ignore_client_bandwidth` behavior update **14** + +**1**: + +New rule actions replace legacy inbound fields and special outbound fields, +and can be used for pre-matching **2**. + +See [Rule](/configuration/route/rule/), +[Rule Action](/configuration/route/rule_action/), +[DNS Rule](/configuration/dns/rule/) and +[DNS Rule Action](/configuration/dns/rule_action/). + +For migration, see +[Migrate legacy special outbounds to rule actions](/migration/#migrate-legacy-special-outbounds-to-rule-actions), +[Migrate legacy inbound fields to rule actions](/migration/#migrate-legacy-inbound-fields-to-rule-actions) +and [Migrate legacy DNS route options to rule actions](/migration/#migrate-legacy-dns-route-options-to-rule-actions). + +**2**: + +Similar to Surge's pre-matching. + +Specifically, new rule actions allow you to reject connections with +TCP RST (for TCP connections) and ICMP port unreachable (for UDP packets) +before connection established to improve tun's compatibility. + +See [Rule Action](/configuration/route/rule_action/). + +**3**: + +When `gvisor` tun stack is enabled, even if the request passes routing, +if the outbound connection establishment fails, +the connection still does not need to be established and a TCP RST is replied. + +**4**: + +Route options in DNS route actions will no longer be considered deprecated, +see [DNS Route Action](/configuration/dns/rule_action/). + +Also, now `udp_disable_domain_unmapping` and `udp_connect` can also be configured in route action, +see [Route Action](/configuration/route/rule_action/). + +**5**: + +When using in graphical clients, new routing rule items allow you to match on +network type (WIFI, cellular, etc.), whether the network is expensive, and whether Low Data Mode is enabled. + +See [Route Rule](/configuration/route/rule/), [DNS Route Rule](/configuration/dns/rule/) +and [Headless Rule](/configuration/rule-set/headless-rule/). + +**6**: + +Similar to Surge's strategy. + +New options allow you to connect using multiple network interfaces, +prefer or only use one type of interface, +and configure a timeout to fallback to other interfaces. + +See [Dial Fields](/configuration/shared/dial/#network_strategy), +[Rule Action](/configuration/route/rule_action/#network_strategy) +and [Route](/configuration/route/#default_network_strategy). + +**7**: + +See [DNS](/configuration/dns/#cache_capacity). + +**8**: + +See [Rule Action](/configuration/route/#override_address) and +[Migrate destination override fields to route options](/migration/#migrate-destination-override-fields-to-route-options). + +**9**: + +The new WireGuard endpoint combines inbound and outbound capabilities, +and the old outbound will be removed in sing-box 1.13.0. + +See [Endpoint](/configuration/endpoint/), [WireGuard Endpoint](/configuration/endpoint/wireguard/) +and [Migrate WireGuard outbound fields to route options](/migration/#migrate-wireguard-outbound-to-endpoint). + +**10**: + +For WireGuard outbound and endpoint, GSO will be automatically enabled when available, +see [WireGuard Outbound](/configuration/outbound/wireguard/#gso). + +For TUN, GSO has been removed, +see [Deprecated](/deprecated/#gso-option-in-tun). + +**11**: + +See [Rule Action](/configuration/route/rule_action/#udp_timeout). + +**12**: + +See [Hysteria2](/configuration/inbound/hysteria2/#masquerade). + +**13**: + +See [Hysteria2](/configuration/outbound/hysteria2/). + +**14**: + +When `up_mbps` and `down_mbps` are set, `ignore_client_bandwidth` instead denies clients from using BBR CC. ### 1.10.7 From bab8dc0b820199ccc47f1bbcceb0037ee5a1fd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 31 Jan 2025 12:57:35 +0800 Subject: [PATCH 09/62] Fix missing handshake for early conn --- route/conn.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/route/conn.go b/route/conn.go index e010c2cd..cbed3491 100644 --- a/route/conn.go +++ b/route/conn.go @@ -225,6 +225,17 @@ func (m *ConnectionManager) connectionCopy(ctx context.Context, source io.Reader } break } + if earlyConn, isEarlyConn := common.Cast[N.EarlyConn](destination); isEarlyConn && earlyConn.NeedHandshake() { + _, err := destination.Write(nil) + if err != nil { + if !direction { + m.logger.ErrorContext(ctx, "connection upload handshake: ", err) + } else { + m.logger.ErrorContext(ctx, "connection download handshake: ", err) + } + return + } + } _, err := bufio.CopyWithCounters(destination, source, originSource, readCounters, writeCounters) if err != nil { common.Close(originDestination) From 27c31eac5d8626251f61f9f6e89961285e2f3bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 1 Feb 2025 19:42:21 +0800 Subject: [PATCH 10/62] Fix local rule-set not updated --- adapter/experimental.go | 10 +++--- experimental/cachefile/cache.go | 6 ++-- route/rule/rule_set_local.go | 39 +++++++++++++++-------- route/rule/rule_set_remote.go | 56 ++++++++++++++++----------------- 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/adapter/experimental.go b/adapter/experimental.go index f22ff9b2..648eb418 100644 --- a/adapter/experimental.go +++ b/adapter/experimental.go @@ -39,17 +39,17 @@ type CacheFile interface { StoreSelected(group string, selected string) error LoadGroupExpand(group string) (isExpand bool, loaded bool) StoreGroupExpand(group string, expand bool) error - LoadRuleSet(tag string) *SavedRuleSet - SaveRuleSet(tag string, set *SavedRuleSet) error + LoadRuleSet(tag string) *SavedBinary + SaveRuleSet(tag string, set *SavedBinary) error } -type SavedRuleSet struct { +type SavedBinary struct { Content []byte LastUpdated time.Time LastEtag string } -func (s *SavedRuleSet) MarshalBinary() ([]byte, error) { +func (s *SavedBinary) MarshalBinary() ([]byte, error) { var buffer bytes.Buffer err := binary.Write(&buffer, binary.BigEndian, uint8(1)) if err != nil { @@ -70,7 +70,7 @@ func (s *SavedRuleSet) MarshalBinary() ([]byte, error) { return buffer.Bytes(), nil } -func (s *SavedRuleSet) UnmarshalBinary(data []byte) error { +func (s *SavedBinary) UnmarshalBinary(data []byte) error { reader := bytes.NewReader(data) var version uint8 err := binary.Read(reader, binary.BigEndian, &version) diff --git a/experimental/cachefile/cache.go b/experimental/cachefile/cache.go index 498b9474..88cffdbe 100644 --- a/experimental/cachefile/cache.go +++ b/experimental/cachefile/cache.go @@ -284,8 +284,8 @@ func (c *CacheFile) StoreGroupExpand(group string, isExpand bool) error { }) } -func (c *CacheFile) LoadRuleSet(tag string) *adapter.SavedRuleSet { - var savedSet adapter.SavedRuleSet +func (c *CacheFile) LoadRuleSet(tag string) *adapter.SavedBinary { + var savedSet adapter.SavedBinary err := c.DB.View(func(t *bbolt.Tx) error { bucket := c.bucket(t, bucketRuleSet) if bucket == nil { @@ -303,7 +303,7 @@ func (c *CacheFile) LoadRuleSet(tag string) *adapter.SavedRuleSet { return &savedSet } -func (c *CacheFile) SaveRuleSet(tag string, set *adapter.SavedRuleSet) error { +func (c *CacheFile) SaveRuleSet(tag string, set *adapter.SavedBinary) error { return c.DB.Batch(func(t *bbolt.Tx) error { bucket, err := c.createBucket(t, bucketRuleSet) if err != nil { diff --git a/route/rule/rule_set_local.go b/route/rule/rule_set_local.go index efbc525e..2b44c50b 100644 --- a/route/rule/rule_set_local.go +++ b/route/rule/rule_set_local.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/sagernet/fswatch" "github.com/sagernet/sing-box/adapter" @@ -26,14 +27,16 @@ import ( var _ adapter.RuleSet = (*LocalRuleSet)(nil) type LocalRuleSet struct { - ctx context.Context - logger logger.Logger - tag string - rules []adapter.HeadlessRule - metadata adapter.RuleSetMetadata - fileFormat string - watcher *fswatch.Watcher - refs atomic.Int32 + ctx context.Context + logger logger.Logger + tag string + rules []adapter.HeadlessRule + metadata adapter.RuleSetMetadata + fileFormat string + watcher *fswatch.Watcher + callbackAccess sync.Mutex + callbacks list.List[adapter.RuleSetUpdateCallback] + refs atomic.Int32 } func NewLocalRuleSet(ctx context.Context, logger logger.Logger, options option.RuleSet) (*LocalRuleSet, error) { @@ -52,13 +55,12 @@ func NewLocalRuleSet(ctx context.Context, logger logger.Logger, options option.R return nil, err } } else { - err := ruleSet.reloadFile(filemanager.BasePath(ctx, options.LocalOptions.Path)) + filePath := filemanager.BasePath(ctx, options.LocalOptions.Path) + filePath, _ = filepath.Abs(options.LocalOptions.Path) + err := ruleSet.reloadFile(filePath) if err != nil { return nil, err } - } - if options.Type == C.RuleSetTypeLocal { - filePath, _ := filepath.Abs(options.LocalOptions.Path) watcher, err := fswatch.NewWatcher(fswatch.Options{ Path: []string{filePath}, Callback: func(path string) { @@ -141,6 +143,12 @@ func (s *LocalRuleSet) reloadRules(headlessRules []option.HeadlessRule) error { metadata.ContainsIPCIDRRule = hasHeadlessRule(headlessRules, isIPCIDRHeadlessRule) s.rules = rules s.metadata = metadata + s.callbackAccess.Lock() + callbacks := s.callbacks.Array() + s.callbackAccess.Unlock() + for _, callback := range callbacks { + callback(s) + } return nil } @@ -173,10 +181,15 @@ func (s *LocalRuleSet) Cleanup() { } func (s *LocalRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] { - return nil + s.callbackAccess.Lock() + defer s.callbackAccess.Unlock() + return s.callbacks.PushBack(callback) } func (s *LocalRuleSet) UnregisterCallback(element *list.Element[adapter.RuleSetUpdateCallback]) { + s.callbackAccess.Lock() + defer s.callbackAccess.Unlock() + s.callbacks.Remove(element) } func (s *LocalRuleSet) Close() error { diff --git a/route/rule/rule_set_remote.go b/route/rule/rule_set_remote.go index 830e19f7..0c5d9bb3 100644 --- a/route/rule/rule_set_remote.go +++ b/route/rule/rule_set_remote.go @@ -33,23 +33,23 @@ import ( var _ adapter.RuleSet = (*RemoteRuleSet)(nil) type RemoteRuleSet struct { - ctx context.Context - cancel context.CancelFunc - outboundManager adapter.OutboundManager - logger logger.ContextLogger - options option.RuleSet - metadata adapter.RuleSetMetadata - updateInterval time.Duration - dialer N.Dialer - rules []adapter.HeadlessRule - lastUpdated time.Time - lastEtag string - updateTicker *time.Ticker - cacheFile adapter.CacheFile - pauseManager pause.Manager - callbackAccess sync.Mutex - callbacks list.List[adapter.RuleSetUpdateCallback] - refs atomic.Int32 + ctx context.Context + cancel context.CancelFunc + logger logger.ContextLogger + outbound adapter.OutboundManager + options option.RuleSet + metadata adapter.RuleSetMetadata + updateInterval time.Duration + dialer N.Dialer + rules []adapter.HeadlessRule + lastUpdated time.Time + lastEtag string + updateTicker *time.Ticker + cacheFile adapter.CacheFile + pauseManager pause.Manager + callbackAccess sync.Mutex + callbacks list.List[adapter.RuleSetUpdateCallback] + refs atomic.Int32 } func NewRemoteRuleSet(ctx context.Context, logger logger.ContextLogger, options option.RuleSet) *RemoteRuleSet { @@ -61,13 +61,13 @@ func NewRemoteRuleSet(ctx context.Context, logger logger.ContextLogger, options updateInterval = 24 * time.Hour } return &RemoteRuleSet{ - ctx: ctx, - cancel: cancel, - outboundManager: service.FromContext[adapter.OutboundManager](ctx), - logger: logger, - options: options, - updateInterval: updateInterval, - pauseManager: service.FromContext[pause.Manager](ctx), + ctx: ctx, + cancel: cancel, + outbound: service.FromContext[adapter.OutboundManager](ctx), + logger: logger, + options: options, + updateInterval: updateInterval, + pauseManager: service.FromContext[pause.Manager](ctx), } } @@ -83,13 +83,13 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter. s.cacheFile = service.FromContext[adapter.CacheFile](s.ctx) var dialer N.Dialer if s.options.RemoteOptions.DownloadDetour != "" { - outbound, loaded := s.outboundManager.Outbound(s.options.RemoteOptions.DownloadDetour) + outbound, loaded := s.outbound.Outbound(s.options.RemoteOptions.DownloadDetour) if !loaded { - return E.New("download_detour not found: ", s.options.RemoteOptions.DownloadDetour) + return E.New("download detour not found: ", s.options.RemoteOptions.DownloadDetour) } dialer = outbound } else { - dialer = s.outboundManager.Default() + dialer = s.outbound.Default() } s.dialer = dialer if s.cacheFile != nil { @@ -286,7 +286,7 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTT } s.lastUpdated = time.Now() if s.cacheFile != nil { - err = s.cacheFile.SaveRuleSet(s.options.Tag, &adapter.SavedRuleSet{ + err = s.cacheFile.SaveRuleSet(s.options.Tag, &adapter.SavedBinary{ LastUpdated: s.lastUpdated, Content: content, LastEtag: s.lastEtag, From 9b4c11ba9597f223d21084e75eeb32ca4b7da930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 1 Feb 2025 19:42:32 +0800 Subject: [PATCH 11/62] Fix rule-set not closed --- route/router.go | 7 +++++++ route/rule/rule_set_local.go | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/route/router.go b/route/router.go index 642340d4..68f5dc35 100644 --- a/route/router.go +++ b/route/router.go @@ -484,6 +484,13 @@ func (r *Router) Close() error { }) monitor.Finish() } + for i, ruleSet := range r.ruleSets { + monitor.Start("close rule-set[", i, "]") + err = E.Append(err, ruleSet.Close(), func(err error) error { + return E.Cause(err, "close rule-set[", i, "]") + }) + monitor.Finish() + } return err } diff --git a/route/rule/rule_set_local.go b/route/rule/rule_set_local.go index 2b44c50b..4f2fabcc 100644 --- a/route/rule/rule_set_local.go +++ b/route/rule/rule_set_local.go @@ -56,7 +56,7 @@ func NewLocalRuleSet(ctx context.Context, logger logger.Logger, options option.R } } else { filePath := filemanager.BasePath(ctx, options.LocalOptions.Path) - filePath, _ = filepath.Abs(options.LocalOptions.Path) + filePath, _ = filepath.Abs(filePath) err := ruleSet.reloadFile(filePath) if err != nil { return nil, err From 7f79458b4f3dd4c2fed470e2a79e5619d6c70f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 1 Feb 2025 19:42:53 +0800 Subject: [PATCH 12/62] Minor updates --- cmd/sing-box/cmd_generate_tls.go | 2 +- common/tls/mkcert.go | 12 ++++++++---- common/tls/std_server.go | 2 +- experimental/locale/locale.go | 2 ++ experimental/locale/locale_zh_CN.go | 1 + 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cmd/sing-box/cmd_generate_tls.go b/cmd/sing-box/cmd_generate_tls.go index d871566f..4cd4060d 100644 --- a/cmd/sing-box/cmd_generate_tls.go +++ b/cmd/sing-box/cmd_generate_tls.go @@ -30,7 +30,7 @@ func init() { } func generateTLSKeyPair(serverName string) error { - privateKeyPem, publicKeyPem, err := tls.GenerateKeyPair(time.Now, serverName, time.Now().AddDate(0, flagGenerateTLSKeyPairMonths, 0)) + privateKeyPem, publicKeyPem, err := tls.GenerateCertificate(nil, nil, time.Now, serverName, time.Now().AddDate(0, flagGenerateTLSKeyPairMonths, 0)) if err != nil { return err } diff --git a/common/tls/mkcert.go b/common/tls/mkcert.go index 1e71a763..12680c48 100644 --- a/common/tls/mkcert.go +++ b/common/tls/mkcert.go @@ -11,8 +11,8 @@ import ( "time" ) -func GenerateCertificate(timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { - privateKeyPem, publicKeyPem, err := GenerateKeyPair(timeFunc, serverName, timeFunc().Add(time.Hour)) +func GenerateKeyPair(parent *x509.Certificate, parentKey any, timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { + privateKeyPem, publicKeyPem, err := GenerateCertificate(parent, parentKey, timeFunc, serverName, timeFunc().Add(time.Hour)) if err != nil { return nil, err } @@ -23,7 +23,7 @@ func GenerateCertificate(timeFunc func() time.Time, serverName string) (*tls.Cer return &certificate, err } -func GenerateKeyPair(timeFunc func() time.Time, serverName string, expire time.Time) (privateKeyPem []byte, publicKeyPem []byte, err error) { +func GenerateCertificate(parent *x509.Certificate, parentKey any, timeFunc func() time.Time, serverName string, expire time.Time) (privateKeyPem []byte, publicKeyPem []byte, err error) { if timeFunc == nil { timeFunc = time.Now } @@ -47,7 +47,11 @@ func GenerateKeyPair(timeFunc func() time.Time, serverName string, expire time.T }, DNSNames: []string{serverName}, } - publicDer, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) + if parent == nil { + parent = template + parentKey = key + } + publicDer, err := x509.CreateCertificate(rand.Reader, template, parent, key.Public(), parentKey) if err != nil { return } diff --git a/common/tls/std_server.go b/common/tls/std_server.go index 8eab87da..1e01bc50 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -222,7 +222,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound } if certificate == nil && key == nil && options.Insecure { tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return GenerateCertificate(ntp.TimeFuncFromContext(ctx), info.ServerName) + return GenerateKeyPair(nil, nil, ntp.TimeFuncFromContext(ctx), info.ServerName) } } else { if certificate == nil { diff --git a/experimental/locale/locale.go b/experimental/locale/locale.go index b1736780..e5575af4 100644 --- a/experimental/locale/locale.go +++ b/experimental/locale/locale.go @@ -7,11 +7,13 @@ var ( type Locale struct { // deprecated messages for graphical clients + Locale string DeprecatedMessage string DeprecatedMessageNoLink string } var defaultLocal = &Locale{ + Locale: "en_US", DeprecatedMessage: "%s is deprecated in sing-box %s and will be removed in sing-box %s please checkout documentation for migration.", DeprecatedMessageNoLink: "%s is deprecated in sing-box %s and will be removed in sing-box %s.", } diff --git a/experimental/locale/locale_zh_CN.go b/experimental/locale/locale_zh_CN.go index 5db2f274..f5605d9d 100644 --- a/experimental/locale/locale_zh_CN.go +++ b/experimental/locale/locale_zh_CN.go @@ -4,6 +4,7 @@ var warningMessageForEndUsers = "\n\n如果您不明白此消息意味着什么 func init() { localeRegistry["zh_CN"] = &Locale{ + Locale: "zh_CN", DeprecatedMessage: "%s 已在 sing-box %s 中被弃用,且将在 sing-box %s 中被移除,请参阅迁移指南。" + warningMessageForEndUsers, DeprecatedMessageNoLink: "%s 已在 sing-box %s 中被弃用,且将在 sing-box %s 中被移除。" + warningMessageForEndUsers, } From 0908627297d50cbe5259b86c563e1ead142727e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 5 Feb 2025 08:58:10 +0800 Subject: [PATCH 13/62] Fix crash on remote rule-set stop --- route/rule/rule_set_remote.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/route/rule/rule_set_remote.go b/route/rule/rule_set_remote.go index 0c5d9bb3..9e0c1729 100644 --- a/route/rule/rule_set_remote.go +++ b/route/rule/rule_set_remote.go @@ -301,8 +301,10 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTT func (s *RemoteRuleSet) Close() error { s.rules = nil - s.updateTicker.Stop() s.cancel() + if s.updateTicker != nil { + s.updateTicker.Stop() + } return nil } From 92d245ad040cbda2f84b21c2a847a470e532c179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 5 Feb 2025 09:55:38 +0800 Subject: [PATCH 14/62] Bump version --- clients/android | 2 +- clients/apple | 2 +- docs/changelog.md | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/android b/clients/android index 599d8cec..6df2f60c 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit 599d8cecacf2ef732b92b3153c08b1b45074661c +Subproject commit 6df2f60c3ad555f6321ec722e1d4f8f609019825 diff --git a/clients/apple b/clients/apple index e43e3a3f..17fed6b9 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit e43e3a3f64886c5ebaa8e41348b4a4e048a0b5b1 +Subproject commit 17fed6b9fcc51aad61638f9aea8827dd1a8f1f0d diff --git a/docs/changelog.md b/docs/changelog.md index c37bdf71..be9e76c5 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,10 @@ icon: material/alert-decagram --- +### 1.11.1 + +* Fixes and improvements + ### 1.11.0 Important changes since 1.10: From c9fb99b79950f47616ed0a04a471c14c5417b6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 6 Feb 2025 08:48:49 +0800 Subject: [PATCH 15/62] Fix missing ENOTCONN in IsClosed check --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1ad0c046..89b67b43 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff github.com/sagernet/quic-go v0.48.2-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.6.0-beta.12 + github.com/sagernet/sing v0.6.0 github.com/sagernet/sing-dns v0.4.0-beta.2 github.com/sagernet/sing-mux v0.3.0-alpha.1 github.com/sagernet/sing-quic v0.4.0-beta.4 diff --git a/go.sum b/go.sum index d2032913..12afbc3e 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.6.0-beta.12 h1:2DnTJcvypK3/PM/8JjmgG8wVK48gdcpRwU98c4J/a7s= -github.com/sagernet/sing v0.6.0-beta.12/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.6.0 h1:jT55zAXrG7H3x+s/FlrC15xQy3LcmuZ2GGA9+8IJdt0= +github.com/sagernet/sing v0.6.0/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-dns v0.4.0-beta.2 h1:HW94bUEp7K/vf5DlYz646LTZevQtJ0250jZa/UZRlbY= github.com/sagernet/sing-dns v0.4.0-beta.2/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8= github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg= From 0d443072d1c2cdb67fe6f503ce5fc85a8765a4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 6 Feb 2025 08:49:25 +0800 Subject: [PATCH 16/62] Fix panic in auto-redirect initialize --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 89b67b43..70f32e31 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 - github.com/sagernet/sing-tun v0.6.0-beta.8 + github.com/sagernet/sing-tun v0.6.0 github.com/sagernet/sing-vmess v0.2.0-beta.2 github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 github.com/sagernet/utls v1.6.7 diff --git a/go.sum b/go.sum index 12afbc3e..c752c78e 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjSsZtRPxiyLV6jyKg0= github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA= -github.com/sagernet/sing-tun v0.6.0-beta.8 h1:GFNt/w8r1v30zC/hfCytk8C9+N/f1DfvosFXJkyJlrw= -github.com/sagernet/sing-tun v0.6.0-beta.8/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= +github.com/sagernet/sing-tun v0.6.0 h1:VBUb4scl74g9ngBxydCMneEZQ07Oiwx4ZFYL9YYYv34= +github.com/sagernet/sing-tun v0.6.0/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= github.com/sagernet/sing-vmess v0.2.0-beta.2 h1:obAkAL35X7ql4RnGzDg4dBYIRpGXRKqcN4LyLZpZGSs= github.com/sagernet/sing-vmess v0.2.0-beta.2/go.mod h1:HGhf9XUdeE2iOWrX0hQNFgXPbKyGlzpeYFyX0c/pykk= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= From a0d4421085b5163c2a05239e44e0c30c49250329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 6 Feb 2025 08:50:21 +0800 Subject: [PATCH 17/62] Update quic-go to v0.49.0 --- go.mod | 10 +++++----- go.sum | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 70f32e31..89464155 100644 --- a/go.mod +++ b/go.mod @@ -24,12 +24,12 @@ require ( github.com/sagernet/fswatch v0.1.1 github.com/sagernet/gomobile v0.1.4 github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff - github.com/sagernet/quic-go v0.48.2-beta.1 + github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.6.0 github.com/sagernet/sing-dns v0.4.0-beta.2 github.com/sagernet/sing-mux v0.3.0-alpha.1 - github.com/sagernet/sing-quic v0.4.0-beta.4 + github.com/sagernet/sing-quic v0.4.0 github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 @@ -43,11 +43,11 @@ require ( github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/crypto v0.31.0 + golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/mod v0.20.0 - golang.org/x/net v0.31.0 - golang.org/x/sys v0.28.0 + golang.org/x/net v0.34.0 + golang.org/x/sys v0.29.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 diff --git a/go.sum b/go.sum index c752c78e..dc6b4827 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.48.2-beta.1 h1:W0plrLWa1XtOWDTdX3CJwxmQuxkya12nN5BRGZ87kEg= -github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k= +github.com/sagernet/quic-go v0.49.0-beta.1 h1:3LdoCzVVfYRibZns1tYWSIoB65fpTmrwy+yfK8DQ8Jk= +github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8WHNsRs71b3Lt1+p/U= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= @@ -125,8 +125,8 @@ github.com/sagernet/sing-dns v0.4.0-beta.2 h1:HW94bUEp7K/vf5DlYz646LTZevQtJ0250j github.com/sagernet/sing-dns v0.4.0-beta.2/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8= github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg= github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE= -github.com/sagernet/sing-quic v0.4.0-beta.4 h1:kKiMLGaxvVLDCSvCMYo4PtWd1xU6FTL7xvUAQfXO09g= -github.com/sagernet/sing-quic v0.4.0-beta.4/go.mod h1:1UNObFodd8CnS3aCT53x9cigjPSCl3P//8dfBMCwBDM= +github.com/sagernet/sing-quic v0.4.0 h1:E4geazHk/UrJTXMlT+CBCKmn8V86RhtNeczWtfeoEFc= +github.com/sagernet/sing-quic v0.4.0/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= @@ -172,16 +172,16 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -191,10 +191,10 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= From 17b502bb4bdc3c7f3966bbad49b18179b814843e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 6 Feb 2025 08:58:56 +0800 Subject: [PATCH 18/62] Update dependencies --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 89464155..2448e4ca 100644 --- a/go.mod +++ b/go.mod @@ -6,16 +6,16 @@ require ( github.com/caddyserver/certmagic v0.20.0 github.com/cloudflare/circl v1.3.7 github.com/cretz/bine v0.2.0 - github.com/go-chi/chi/v5 v5.1.0 + github.com/go-chi/chi/v5 v5.2.1 github.com/go-chi/render v1.0.3 github.com/gofrs/uuid/v5 v5.3.0 - github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 + github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 github.com/libdns/alidns v1.0.3 github.com/libdns/cloudflare v0.1.1 github.com/logrusorgru/aurora v2.0.3+incompatible - github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa + github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 github.com/mholt/acmez v1.2.0 - github.com/miekg/dns v1.1.62 + github.com/miekg/dns v1.1.63 github.com/oschwald/maxminddb-golang v1.12.0 github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a @@ -27,27 +27,27 @@ require ( github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.6.0 - github.com/sagernet/sing-dns v0.4.0-beta.2 - github.com/sagernet/sing-mux v0.3.0-alpha.1 + github.com/sagernet/sing-dns v0.4.0 + github.com/sagernet/sing-mux v0.3.1 github.com/sagernet/sing-quic v0.4.0 github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 - github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 + github.com/sagernet/sing-shadowtls v0.2.0 github.com/sagernet/sing-tun v0.6.0 - github.com/sagernet/sing-vmess v0.2.0-beta.2 + github.com/sagernet/sing-vmess v0.2.0 github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 github.com/sagernet/utls v1.6.7 github.com/sagernet/wireguard-go v0.0.1-beta.5 github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/mod v0.20.0 golang.org/x/net v0.34.0 - golang.org/x/sys v0.29.0 + golang.org/x/sys v0.30.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 diff --git a/go.sum b/go.sum index dc6b4827..7a36c171 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbY github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -47,8 +47,8 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8 github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= -github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= +github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= +github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -74,12 +74,12 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= -github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa h1:9mcjV+RGZVC3reJBNDjjNPyS8PmFG97zq56X7WNaFO4= -github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa/go.mod h1:4tLB5c8U0CxpkFM+AJJB77jEaVDbLH5XQvy42vAGsWw= +github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= +github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= @@ -121,22 +121,22 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4Wk github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.6.0 h1:jT55zAXrG7H3x+s/FlrC15xQy3LcmuZ2GGA9+8IJdt0= github.com/sagernet/sing v0.6.0/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-dns v0.4.0-beta.2 h1:HW94bUEp7K/vf5DlYz646LTZevQtJ0250jZa/UZRlbY= -github.com/sagernet/sing-dns v0.4.0-beta.2/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8= -github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg= -github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE= +github.com/sagernet/sing-dns v0.4.0 h1:+mNoOuR3nljjouCH+qMg4zHI1+R9T2ReblGFkZPEndc= +github.com/sagernet/sing-dns v0.4.0/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= +github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= +github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78= github.com/sagernet/sing-quic v0.4.0 h1:E4geazHk/UrJTXMlT+CBCKmn8V86RhtNeczWtfeoEFc= github.com/sagernet/sing-quic v0.4.0/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= -github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjSsZtRPxiyLV6jyKg0= -github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA= +github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk= +github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= github.com/sagernet/sing-tun v0.6.0 h1:VBUb4scl74g9ngBxydCMneEZQ07Oiwx4ZFYL9YYYv34= github.com/sagernet/sing-tun v0.6.0/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= -github.com/sagernet/sing-vmess v0.2.0-beta.2 h1:obAkAL35X7ql4RnGzDg4dBYIRpGXRKqcN4LyLZpZGSs= -github.com/sagernet/sing-vmess v0.2.0-beta.2/go.mod h1:HGhf9XUdeE2iOWrX0hQNFgXPbKyGlzpeYFyX0c/pykk= +github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI= +github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8= @@ -152,8 +152,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= @@ -191,8 +191,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From a2d40eb8b8f53f9c5059223a0d415e03f0a0f0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 6 Feb 2025 11:20:18 +0800 Subject: [PATCH 19/62] Fix override UDP destination --- route/route.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/route/route.go b/route/route.go index bb29261c..bad7922b 100644 --- a/route/route.go +++ b/route/route.go @@ -489,12 +489,8 @@ match: break match } } - if !preMatch && inputPacketConn != nil && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() { - var timeout time.Duration - if metadata.InboundType == C.TypeSOCKS { - timeout = C.TCPTimeout - } - newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{Timeout: timeout}, inputConn, inputPacketConn) + if !preMatch && inputPacketConn != nil && (metadata.InboundType == C.TypeSOCKS || metadata.InboundType == C.TypeMixed) && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() { + newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{Timeout: C.TCPTimeout}, inputConn, inputPacketConn) if newErr != nil { fatalErr = newErr return @@ -590,7 +586,7 @@ func (r *Router) actionSniff( return } } else { - if !metadata.Destination.Addr.IsGlobalUnicast() { + if (metadata.InboundType == C.TypeSOCKS || metadata.InboundType == C.TypeMixed) && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() { metadata.Destination = destination } if len(packetBuffers) > 0 { From 8d6c4f1289f31b28d955da05c59d9a297aed50bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 31 Jan 2025 11:59:35 +0800 Subject: [PATCH 20/62] release: Skip testflight when another build in review --- cmd/internal/app_store_connect/main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/internal/app_store_connect/main.go b/cmd/internal/app_store_connect/main.go index ef006738..6eb1e7e0 100644 --- a/cmd/internal/app_store_connect/main.go +++ b/cmd/internal/app_store_connect/main.go @@ -5,6 +5,7 @@ import ( "net/http" "os" "strconv" + "strings" "time" "github.com/sagernet/asc-go/asc" @@ -194,6 +195,10 @@ func publishTestflight(ctx context.Context) error { log.Info(string(platform), " ", tag, " create submission") _, _, err = client.TestFlight.CreateBetaAppReviewSubmission(ctx, build.ID) if err != nil { + if strings.Contains(err.Error(), "ANOTHER_BUILD_IN_REVIEW") { + log.Error(err) + break + } return err } } From abc38d1dab6640bd23e93f90069f4ea9398de971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 10 Feb 2025 15:11:26 +0800 Subject: [PATCH 21/62] Fix udpnat2 crash --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2448e4ca..511aea0b 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.6.0 + github.com/sagernet/sing v0.6.1 github.com/sagernet/sing-dns v0.4.0 github.com/sagernet/sing-mux v0.3.1 github.com/sagernet/sing-quic v0.4.0 diff --git a/go.sum b/go.sum index 7a36c171..42abdb9b 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.6.0 h1:jT55zAXrG7H3x+s/FlrC15xQy3LcmuZ2GGA9+8IJdt0= -github.com/sagernet/sing v0.6.0/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA= +github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-dns v0.4.0 h1:+mNoOuR3nljjouCH+qMg4zHI1+R9T2ReblGFkZPEndc= github.com/sagernet/sing-dns v0.4.0/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= From 4eed46ac5998945b604e4d0152907f61d3b1c50c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 10 Feb 2025 15:12:03 +0800 Subject: [PATCH 22/62] Fix respond ICMP echo --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 511aea0b..b75ceb34 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowtls v0.2.0 - github.com/sagernet/sing-tun v0.6.0 + github.com/sagernet/sing-tun v0.6.1 github.com/sagernet/sing-vmess v0.2.0 github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 github.com/sagernet/utls v1.6.7 diff --git a/go.sum b/go.sum index 42abdb9b..9ffef2d4 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk= github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= -github.com/sagernet/sing-tun v0.6.0 h1:VBUb4scl74g9ngBxydCMneEZQ07Oiwx4ZFYL9YYYv34= -github.com/sagernet/sing-tun v0.6.0/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= +github.com/sagernet/sing-tun v0.6.1 h1:4l0+gnEKcGjlWfUVTD+W0BRApqIny/lU2ZliurE+VMo= +github.com/sagernet/sing-tun v0.6.1/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI= github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= From 9db2d58545b4de9a3453b296125eed0fe823ad17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 2 Feb 2025 23:17:31 +0800 Subject: [PATCH 23/62] Fix override address --- route/conn.go | 6 ++++++ route/route.go | 2 +- route/rule/rule_action.go | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/route/conn.go b/route/conn.go index cbed3491..1c0d3c90 100644 --- a/route/conn.go +++ b/route/conn.go @@ -159,6 +159,12 @@ func (m *ConnectionManager) NewPacketConnection(ctx context.Context, this N.Dial if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { natConn.UpdateDestination(destinationAddress) } + } else if metadata.RouteOriginalDestination.IsValid() && metadata.RouteOriginalDestination != metadata.Destination { + if metadata.UDPDisableDomainUnmapping { + remotePacketConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination) + } else { + remotePacketConn = bufio.NewNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination) + } } var udpTimeout time.Duration if metadata.UDPTimeout > 0 { diff --git a/route/route.go b/route/route.go index bad7922b..edf6063e 100644 --- a/route/route.go +++ b/route/route.go @@ -586,7 +586,7 @@ func (r *Router) actionSniff( return } } else { - if (metadata.InboundType == C.TypeSOCKS || metadata.InboundType == C.TypeMixed) && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() { + if (metadata.InboundType == C.TypeSOCKS || metadata.InboundType == C.TypeMixed) && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() && !metadata.RouteOriginalDestination.IsValid() { metadata.Destination = destination } if len(packetBuffers) > 0 { diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index f4f2299a..8989ff3c 100644 --- a/route/rule/rule_action.go +++ b/route/rule/rule_action.go @@ -162,6 +162,24 @@ func (r *RuleActionRouteOptions) Type() string { func (r *RuleActionRouteOptions) String() string { var descriptions []string + if r.OverrideAddress.IsValid() { + descriptions = append(descriptions, F.ToString("override-address=", r.OverrideAddress.AddrString())) + } + if r.OverridePort > 0 { + descriptions = append(descriptions, F.ToString("override-port=", r.OverridePort)) + } + if r.NetworkStrategy != nil { + descriptions = append(descriptions, F.ToString("network-strategy=", r.NetworkStrategy)) + } + if r.NetworkType != nil { + descriptions = append(descriptions, F.ToString("network-type=", strings.Join(common.Map(r.NetworkType, C.InterfaceType.String), ","))) + } + if r.FallbackNetworkType != nil { + descriptions = append(descriptions, F.ToString("fallback-network-type="+strings.Join(common.Map(r.NetworkType, C.InterfaceType.String), ","))) + } + if r.FallbackDelay > 0 { + descriptions = append(descriptions, F.ToString("fallback-delay=", r.FallbackDelay.String())) + } if r.UDPDisableDomainUnmapping { descriptions = append(descriptions, "udp-disable-domain-unmapping") } From 986a410b3066a6129c3deb0175476977aafcf3aa Mon Sep 17 00:00:00 2001 From: printfer <16911871+printfer@users.noreply.github.com> Date: Mon, 10 Feb 2025 02:35:20 -0400 Subject: [PATCH 24/62] documentation: Fix migration links --- docs/migration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/migration.md b/docs/migration.md index c8b876f7..4943bb86 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -108,7 +108,7 @@ Inbound fields are deprecated and can be replaced by rule actions. !!! info "References" - [Listen Fields](/configuration/inbound/listen/) / + [Listen Fields](/configuration/shared/listen/) / [Rule](/configuration/route/rule/) / [Rule Action](/configuration/route/rule_action/) / [DNS Rule](/configuration/dns/rule/) / From badfdb62cd2030430a496325d5c6ad4152ebc3ab Mon Sep 17 00:00:00 2001 From: ReleTor <191429954+reletor@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:33:41 +0800 Subject: [PATCH 25/62] documentation: Fixes --- docs/configuration/index.zh.md | 2 ++ docs/configuration/outbound/block.md | 2 +- docs/configuration/rule-set/index.md | 2 +- docs/configuration/rule-set/index.zh.md | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/configuration/index.zh.md b/docs/configuration/index.zh.md index 6aeb4857..b639c72a 100644 --- a/docs/configuration/index.zh.md +++ b/docs/configuration/index.zh.md @@ -8,6 +8,7 @@ sing-box 使用 JSON 作为配置文件格式。 { "log": {}, "dns": {}, + "ntp": {}, "endpoints": [], "inbounds": [], "outbounds": [], @@ -22,6 +23,7 @@ sing-box 使用 JSON 作为配置文件格式。 |----------------|------------------------| | `log` | [日志](./log/) | | `dns` | [DNS](./dns/) | +| `ntp` | [NTP](./ntp/) | | `endpoints` | [端点](./endpoint/) | | `inbounds` | [入站](./inbound/) | | `outbounds` | [出站](./outbound/) | diff --git a/docs/configuration/outbound/block.md b/docs/configuration/outbound/block.md index f29120cc..1be04dd5 100644 --- a/docs/configuration/outbound/block.md +++ b/docs/configuration/outbound/block.md @@ -8,7 +8,7 @@ icon: material/delete-clock ### Structure -```json F +```json { "type": "block", "tag": "block" diff --git a/docs/configuration/rule-set/index.md b/docs/configuration/rule-set/index.md index bed3fb54..c905e110 100644 --- a/docs/configuration/rule-set/index.md +++ b/docs/configuration/rule-set/index.md @@ -74,7 +74,7 @@ Tag of rule-set. ==Required== -List of [Headless Rule](../headless-rule/). +List of [Headless Rule](./headless-rule/). ### Local or Remote Fields diff --git a/docs/configuration/rule-set/index.zh.md b/docs/configuration/rule-set/index.zh.md index 083c06bd..c3b86b6d 100644 --- a/docs/configuration/rule-set/index.zh.md +++ b/docs/configuration/rule-set/index.zh.md @@ -74,7 +74,7 @@ icon: material/new-box ==必填== -一组 [无头规则](../headless-rule/). +一组 [无头规则](./headless-rule/). ### 本地或远程字段 From 07ac01dcb794119b5d943c6950d1402ea1f9f82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 10 Feb 2025 15:44:49 +0800 Subject: [PATCH 26/62] platform: Update NDK to r28 --- .github/workflows/build.yml | 6 +++--- cmd/internal/build_shared/sdk.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 000ac3e9..61f14cfb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -153,7 +153,7 @@ jobs: if: matrix.goos == 'android' uses: nttld/setup-ndk@v1 with: - ndk-version: r28-beta2 + ndk-version: r28 local-cache: true - name: Setup Goreleaser uses: goreleaser/goreleaser-action@v6 @@ -224,7 +224,7 @@ jobs: id: setup-ndk uses: nttld/setup-ndk@v1 with: - ndk-version: r28-beta3 + ndk-version: r28 - name: Setup OpenJDK run: |- sudo apt update && sudo apt install -y openjdk-17-jdk-headless @@ -299,7 +299,7 @@ jobs: id: setup-ndk uses: nttld/setup-ndk@v1 with: - ndk-version: r28-beta3 + ndk-version: r28 - name: Setup OpenJDK run: |- sudo apt update && sudo apt install -y openjdk-17-jdk-headless diff --git a/cmd/internal/build_shared/sdk.go b/cmd/internal/build_shared/sdk.go index eab95216..5061c321 100644 --- a/cmd/internal/build_shared/sdk.go +++ b/cmd/internal/build_shared/sdk.go @@ -48,7 +48,7 @@ func FindSDK() { } func findNDK() bool { - const fixedVersion = "28.0.12916984" + const fixedVersion = "28.0.13004108" const versionFile = "source.properties" if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.IsFile(filepath.Join(fixedPath, versionFile)) { androidNDKPath = fixedPath From fbe390268c7334928f304dc63e84643d3b44df0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 10 Feb 2025 19:11:26 +0800 Subject: [PATCH 27/62] Bump version --- clients/android | 2 +- clients/apple | 2 +- docs/changelog.md | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/android b/clients/android index 6df2f60c..601e5c15 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit 6df2f60c3ad555f6321ec722e1d4f8f609019825 +Subproject commit 601e5c1571261691c360d3a017a7aab0551f2b56 diff --git a/clients/apple b/clients/apple index 17fed6b9..ae8c4ceb 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit 17fed6b9fcc51aad61638f9aea8827dd1a8f1f0d +Subproject commit ae8c4ceb6e74fc07780075530747d9eeec1888f1 diff --git a/docs/changelog.md b/docs/changelog.md index be9e76c5..8a8dd9e3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,10 @@ icon: material/alert-decagram --- +### 1.11.2 + +* Fixes and improvements + ### 1.11.1 * Fixes and improvements From ff31c469a061656f17aafb29b35d3fc297a66439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 11 Feb 2025 14:41:41 +0800 Subject: [PATCH 28/62] Override version --- clients/android | 2 +- clients/apple | 2 +- cmd/internal/update_android_version/main.go | 6 ++++-- docs/changelog.md | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/clients/android b/clients/android index 601e5c15..3a2fc9c8 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit 601e5c1571261691c360d3a017a7aab0551f2b56 +Subproject commit 3a2fc9c8802f0c40f0b1fd2d7acdcabb7aa0855f diff --git a/clients/apple b/clients/apple index ae8c4ceb..3d5d7343 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit ae8c4ceb6e74fc07780075530747d9eeec1888f1 +Subproject commit 3d5d7343fb473dce772633183791524629493213 diff --git a/cmd/internal/update_android_version/main.go b/cmd/internal/update_android_version/main.go index 0c6528c6..7f27903b 100644 --- a/cmd/internal/update_android_version/main.go +++ b/cmd/internal/update_android_version/main.go @@ -46,21 +46,23 @@ func main() { switch propPair[0] { case "VERSION_NAME": if propPair[1] != newVersion { + log.Info("updated version from ", propPair[1], " to ", newVersion) versionUpdated = true propPair[1] = newVersion - log.Info("updated version to ", newVersion) } case "GO_VERSION": if propPair[1] != runtime.Version() { + log.Info("updated Go version from ", propPair[1], " to ", runtime.Version()) goVersionUpdated = true propPair[1] = runtime.Version() - log.Info("updated Go version to ", runtime.Version()) } } } if !(versionUpdated || goVersionUpdated) { log.Info("version not changed") return + } else if flagRunInCI { + log.Fatal("version changed, commit changes first.") } for _, propPair := range propsList { switch propPair[0] { diff --git a/docs/changelog.md b/docs/changelog.md index 8a8dd9e3..c1d7ba89 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,10 +2,12 @@ icon: material/alert-decagram --- -### 1.11.2 +### 1.11.3 * Fixes and improvements +_This version overwrites 1.11.2, as incorrect binaries were released due to a bug in the continuous integration process._ + ### 1.11.1 * Fixes and improvements From 093013687c0c66a323e22d10191d675a7e7da570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 18 Feb 2025 18:12:53 +0800 Subject: [PATCH 29/62] Fix sniff QUIC hidden in three or more packets --- common/sniff/quic_test.go | 20 ++++++++++++++++++++ route/route.go | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/common/sniff/quic_test.go b/common/sniff/quic_test.go index e75e86a5..1fbf6096 100644 --- a/common/sniff/quic_test.go +++ b/common/sniff/quic_test.go @@ -12,6 +12,26 @@ import ( "github.com/stretchr/testify/require" ) +func TestSniffQUICChromeNew(t *testing.T) { + t.Parallel() + pkt, err := hex.DecodeString("ca0000000108e241a0c601413b4f004046006d8f15dae9999edf39d58df6762822b9a2ab996d7f6a10044338af3b51b1814bc4ac0fa5a87c34c6ae604af8cabc5957c5240174deefc8e378719ffdab2ae4e15bf4514bea4489ad89c322f75f9a383c90d126a0b21104cb519c2bb32e6a134e86896452e942b26c519b8c7ac9e4c99fae5e1f65cf08fb98443b30e4567932e8fb0789820d8f33037b59ac8113530258c9467dfb52489396dae01f099d28b234efa107fa411f2a1ffa2abe74988e03d662d4296024e95ce0fe1671724937157f77b84990478a2d4060676cf0827b4e8c600654111750414dafa0cccb332f3020c2922a015f445df5edc9c7d2d1ceea9fddcc9ff821c9183aa39a70da20fcc057579e1051c1c899148d6cf9d08b4919822082d040d1ce03ca4f216be6cb7ef03db6df0993ef1ccce5c8c648980554f41704526e1809d2545739f5872e75ec797db1c99f5682e2eda9363cb32aa367b7b363c782ddbacf874183cc15c8a2db068dd4093eebdd096ad33832a7939deb0a872279744f5a56dc001ba62fac973bf680f3b362bdd336add4dd102f462b773bf70bfce1921070a802a92025273a177186d1a643081b42175eb789ccddadb71033ef4feacbf6fd282ab622cf61669d73cda559e411c6ccdd8f003443b6933b7729b7a357aa4aa2fba0f365f829a4d497afb5dc2648a53bc9f3e786d955069d0a4781088a5463747dfe9958ea19ea444eae947ec6a67640955f710f93640084f3fbb8ad259b68dbc0ee0b7fab2d81bffd83ed8a6d33522dbfef43bec0a0fb4bdf1cb712dc4ced0680c0687fa240fd157baa232b1c84e14adce6421cf9270f9b3972f98fc67b344b8a4f1fb551e26f7f76d484ed9f8197f231dc5d9a44cc0ddce73d7f810a620851f4e97eb5037ab5135d7c3be5b80cc32d19910b8387aca64c93c02dc3e35238b78e6aff470722078982e58802844932b6041446bfdcc97ba640cbb86721bcd0f40f27b77aa6287ce5674ec1720134b9302875482c3269787e004b9edb483d44f326eef38c0e83cb46af96488c2e696bc2524567fb29c1e8edcd5a73615496d172d46a9d29e0505c0018b7bbb00165eca0389e09c4b1d73b6cc4a2f735a720650134a2e98e8105e20695cf231b92586237dfe0f99c897414e51c21627496276535f07abb53fb2b554376fe520fa45a3e944fd91dfe7a72aead08842b6b63d8edf861fb911954c83bd9a896eb9da4af5eff646455069d747facd4e77c254096843bff7c3e9031dbdf8dc37ea45f1122922fcbc322ec1378f3c7c1af0da62e1052e6210f1b23073f93a82d90e14cb20bc4501d487a1c848674d57a7c269b13590b3a99d8b8b4f6d0dfbd1d2cbbe7a32c0d5c84ae7ec438b0b19f3862d8fabaa828d06c7e3c6967405cd56a1ae90f38633e2ee0e3ecfca3df399fe12f029e0860a1a30da010300d0c94f0bf56091d00011488c1429928b21c739ebf50ba8be91116315d3173f6d2c56735722478c4d74392ba84d1727036b3d64e8c2263b0f33cb8086be587ca6b3940259c06afa2683868856529303ae12e91d7ca874568be7f2bfaa0656dfab0ed31ed90eaea10fb7f3433ec59a334abe6211d547fa0c825ac45d3691e749d15432008de83e9f6d98f368359137ae803d9189b3386f800c7c0cf4b615d1983cf82d9981a8105b60a80fe66c9b0d439b5ba153dd19e9e7483a01cf3b02b4597540b38e658d4eb8455e030b2bf2690bdd78c23f16fe5") + require.NoError(t, err) + var metadata adapter.InboundContext + err = sniff.QUICClientHello(context.Background(), &metadata, pkt) + require.Equal(t, metadata.Protocol, C.ProtocolQUIC) + require.Equal(t, metadata.Client, C.ClientChromium) + require.ErrorIs(t, err, sniff.ErrClientHelloFragmented) + pkt, err = hex.DecodeString("cc0000000108e241a0c601413b4f004046006d8f15dae9999edf39d58df6762822b9a2ab996d7f6a10044338af3b51b1814bc4ac0fa5a87c34c6ae604af8cabc5957c5240174deefc8e378719ffdab2ae4e15bf4514bea44894b626c685cd5d5c965f7e97b3a1bdc520b75813e747f37a3ae83ad38b9ca2acb0de4fc9424839a50c8fb815a62b498609fbbc59145698860e0509cc08a04d1b119daef844ba2f09c16e2665e5cc0b47624b71f7b950c54fd56b4a1fbb826cba44eeeee3949ced8f5de60d4c81b19ee59f75aa1abb33f22c6b13c27095eb1e99cff01fdc93e6e88da2622ee18c08a79f508befd7e33e99bca60e64bef9a47b764384bd93823daeeb6fcb4d7cfbc4ab53eff59b3636f6dcaaf229b5a94941b5712807166b9bd5e82cb4a9708a71451c4cd6f6e33fb2fe40c8c70dd51a30b37ff9c5e35783debde0093fde19ce074b4887b3c90980b107b9c0f32cf61a66f37c251b789abc4d27fc421207966846c8cc7faa42d9af6ad355a6bc94cb78223b612be8b3e2a4df61fee83a674a0ceb8b7c3a29b97102cda22fecdf6a4628e5b612bc17eab64d6f75feedd0b106c0419e484e66725759964cb5935ac5125e5ae920cd280bd40df57c1d7ae1845700bd4eb7b7ab12bc0850950bfe6e69edd6ac1daa5db2c2b07484327196e561c513462d72872dc6771c39f6b60d46a1f2c92343b7338450a0ef8e39f97fa70652b3a12cd04043698951627aaaa82cc95e76df92021d30e8014c984f12eea0143de8b17e5e4a36ec07bf4814251b391f168a59ef75afcd2319249aaba930f06bb7a11b9491e6f71b3d5774a6503a965e94edd0a67737282fc9cb0271779ff14151b7aa9267bb8f7d643185512515aeea513c0c98bfae782381a3317064195d8825cf8b25c17cdab5fced02612a3f2870e40df57e6ca3f08228a2b04e8de1425eb4b970118f9bbdc212223ff86a5d6b648cdf2366722f21de4b14a1014879eadb69215cdb1aa2a9f4f310ecfe3116214fe3ab0a23f4775a0a54b48d7dfd8f7283ed687b3ac7e1a7e42a0bdc3478aba8651c03e1e9cc9df17d106b8130afe854269b0103b7a696f452721887b19d8181830073c9f10684c65f96d3a6c6efbae044eec03d6399e001fa44d54635dc72f9b8ea6b87d0f452cad1e1e32273e2b47c40f2730235adcae8523b8282f86b8cf1ab63ae54aaa06130df3bbf6ecac7d7d1d43d2a87aea837267ff8ccfaa4b7e47b7ded909e6603d0b928a304f8915c839153598adc4178eb48bc0e98ad7793d7980275e1e491ba4847a4a04ae30fe7f5cc7d4b6f4f63a525e9964d72245860ca76a668a4654adb6619f16e9db79131e5675b93cafb96c92f1da8464d4fef2a22e7f9db695965fe2cc27ea30974629c8fe17cfa2f860179e1eb9faaa88a91ec9ce6da28c1a2894c3b932b5e1c807146718cc77ca13c61eaae00c7c99e019f599772064b198c5c2c5e863336367673630b417ac845ddb7c93b0856317e5d64bab208c5730abc2c63536784fbeaaec139dffc917e775715f1e42164ddef5138d4d163609ab3fbdcab968f8738385c0e7e34ff3cf7771a1dc5ba25a8850fdf96dabafa21f9065f307457ce9af4b7a73450c9d20a3b46fa8d3a1163d22bd01a7d17f0ec274181bf9640fa941427694bfeb1346089f7a851efe0fbb7a2041fa6bb6541ccbad77dd3e1a97999fc05f1fef070e7b5c4b385b8b2a8cc32483fdeba6a373970de2fa4139ba18e5916f949aab0aab2894") + require.NoError(t, err) + err = sniff.QUICClientHello(context.Background(), &metadata, pkt) + require.ErrorIs(t, err, sniff.ErrClientHelloFragmented) + pkt, err = hex.DecodeString("c20000000108e241a0c601413b4f004046006d8f15dae9999edf39d58df6762822b9a2ab996d7f6a10044338af3b51b1814bc4ac0fa5a87c34c6ae604af8cabc5957c5240174deefc8e378719ffdab2ae4e15bf4514bea4489e2ff30c43a5f63beb2e4501ce7754085bcbe838003a0b4bccb53863c0766df7eac073c2bdc170772b157997945acdc2ab2e84750cc9aa0ffa0fdc023da7fc565a14f87f7c563dbc9183dd226aab79957d263f66e64b85a1b15a24516bd2c7c04eea4fa0a34ef9849c21585db2e4adb7c05e265c4f38d8ffe4cbed0f3b0e68f3693bf1f726c3fb135b8e32a5d22931d7c55fc2ff4b9a354933ab14544df3cdaf3e3217dfb8d7feb3465dc34df6320ea486f12e5b2d609aaa5f4515c20c86fc440f8087be0ee3d339835746ae2573c2afdee6bb6ef7e9eb541feae9209391b2902cfb0bdaccd9da8d290714638b7da588d4a656ca6eabba78b7363922d6037cf060b161a42019d4feb4156459103cffdeefd0e63114af2b0e0c39e70ebc7fecb8dd1ebb8d60b2137f509bb7dcef5f1d3e06ab1d391466652d57440a410fb4f58a6ce1fb62feb453241f64e110709f59a3d9ebdac94f811337d0e4a80fd6b56b2a70cd6eebbf98e1661291da6bf5beb8b8afc376dfd20eb76afe709e8e8f28e0ef82105954e346546ad25973df43f4acddbec0ffd9b215f62abebebf71305b5ea993560316f69430bf5afe50420340622f802b5830f3bcebffff04980c75a59d28902879e5d51a4fb21062a4ae13c42297075b21d54ee04303879c1157e7470c1451673c98a2f3921f2f3e8f6acfe85b01caaca66b59e5ebffbfe68e5e9ab17e9a1b857eb409df91cb76767fc1814fd3c522a9b117edd0b02526e469cb4afb291a4dcc74c79b47ec6e7ce558c597129366f83ec306b11d2598c705fd4ee9ee99df6b7039bef13b08fc6f26853ad213829d24f895747d45a47414f931c583fb6c3e4f6c27d0c2b81a5f3cee390ec6314e1fec637e8d28b675e97caafdfbf8c25d34a635083a7553d219dd80dbb39087d74c6ad6192ca6f48a3ff8d47db41b2a492c63fcd780012780931dae0a325f9dcbd772d09a700f132c4bc1d9809b25b9751b694eb72a8ba4db7208d2b1bab63e1845208e4f841ea30218a559db98751589716b6d059ca673378f5fe7c7d8a1c82e14a561c47313bbcc278412ba86ffb2b87ec308eab9df696f5b4b54f8e361731bf232820a02a35fda7e5d4bf01b8f005ad299a055116e7b23c181f15a66442cf6032ca477bccc55b79d424eb4f245847bd81a581dc369dd20b1a4892733bde3c38e492c0039f69f2b947a4dc251a49ee7ccc0f36b3b75a555fa1d126db75f94dab60f52f6b15a877a0c380b59f82d35c570bc5f8051e9ef87db51f52383d47b50829b7f9e947ccc67aa280566aa48b4a85c1c7eca6f542789d8abcc050f1aa3cc221b6859656a21454aa21c7bfb9d12115f61c3ed46263ade68a8d3679fa62a659a5da7817406bd16618fccf33ed208ada1b03584e8b485d3cb6ed80a0774e60b6cd55aff64169ea998cf8235997049515abac58e0169ca07fb1c8c4c8b2803ba9d27b44c045d0a1cac86e5e188195c68001f53eb44851b6d821fc01ccbb41e27f38e6ddd66540c2d62ed6e0d551e22c0f26b60078c74a6302a1ed3d9e8fc0861257a63f6ac4e759fd54bff088becd28e30944a6c15db4fc8ae6244346869add946d9d92c430d737e042fa18b28a8ed64d1e8987ad9061cdc1335f") + require.NoError(t, err) + err = sniff.QUICClientHello(context.Background(), &metadata, pkt) + require.NoError(t, err) + require.Equal(t, "www.google.com", metadata.Domain) +} + func TestSniffQUICChromium(t *testing.T) { t.Parallel() pkt, err := hex.DecodeString("c30000000108f40d654cc09b27f5000044d08a94548e57e43cc5483f129986187c432d58d46674830442988f869566a6e31e2ae37c9f7acbf61cc81621594fab0b3dfdc1635460b32389563dc8e74006315661cd22694114612973c1c45910621713a48b375854f095e8a77ccf3afa64e972f0f7f7002f50e0b014b1b146ea47c07fb20b73ad5587872b51a0b3fafdf1c4cf4fe6f8b112142392efa25d993abe2f42582be145148bdfe12edcd96c3655b65a4781b093e5594ba8e3ae5320f12e8314fc3ca374128cc43381046c322b964681ed4395c813b28534505118201459665a44b8f0abead877de322e9040631d20b05f15b81fa7ff785d4041aecc37c7e2ccdc5d1532787ce566517e8985fd5c200dbfd1e67bc255efaba94cfc07bb52fea4a90887413b134f2715b5643542aa897c6116486f428d82da64d2a2c1e1bdd40bd592558901a554b003d6966ac5a7b8b9413eddbf6ef21f28386c74981e3ce1d724c341e95494907626659692720c81114ca4acea35a14c402cfa3dc2228446e78dc1b81fa4325cf7e314a9cad6a6bdff33b3351dcba74eb15fae67f1227283aa4cdd64bcadf8f19358333f8549b596f4350297b5c65274565869d497398339947b9d3d064e5b06d39d34b436d8a41c1a3880de10bd26c3b1c5b4e2a49b0d4d07b8d90cd9e92bc611564d19ea8ec33099e92033caf21f5307dbeaa4708b99eb313bff99e2081ac25fd12d6a72e8335e0724f6718fe023cd0ad0d6e6a6309f09c9c391eec2bc08e9c3210a043c08e1759f354c121f6517fff4d6e20711a871e41285d48d930352fddffb92c96ba57df045ce99f8bfdfa8edc0969ce68a51e9fbb4f54b956d9df74a9e4af27ed2b27839bce1cffeca8333c0aaee81a570217442f9029ba8fedb84a2cf4be4d910982d891ea00e816c7fb98e8020e896a9c6fdd9106611da0a99dde18df1b7a8f6327acb1eed9ad93314451e48cb0dfb9571728521ca3db2ac0968159d5622556a55d51a422d11995b650949aaefc5d24c16080446dfc4fbc10353f9f93ce161ab513367bb89ab83988e0630b689e174e27bcfcc31996ee7b0bca909e251b82d69a28fee5a5d662e127508cd19dbbe5097b7d5b62a49203d66764197a527e472e2627e44a93d44177dace9d60e7d0e03305ddf4cfe47cdf2362e14de79ef46a6763ce696cd7854a48d9419a0817507a4713ffd4977b906d4f2b5fb6dbe1bd15bc505d5fea582190bf531a45d5ee026da8918547fd5105f15e5d061c7b0cf80a34990366ed8e91e13c2f0d85e5dad537298808d193cf54b7eaac33f10051f74cb6b75e52f81618c36f03d86aef613ba237a1a793ba1539938a38f62ccaf7bd5f6c5e0ce53cde4012fcf2b758214a0422d2faaa798e86e19d7481b42df2b36a73d287ff28c20cce01ce598771fec16a8f1f00305c06010126013a6c1de9f589b4e79d693717cd88ad1c42a2d99fa96617ba0bc6365b68e21a70ebc447904aa27979e1514433cfd83bfec09f137c747d47582cb63eb28f873fb94cf7a59ff764ddfbb687d79a58bb10f85949269f7f72c611a5e0fbb52adfa298ff060ec2eb7216fd7302ea8fb07798cbb3be25cb53ac8161aac2b5bbcfbcfb01c113d28bd1cb0333fb89ac82a95930f7abded0a2f5a623cc6a1f62bf3f38ef1b81c1e50a634f657dbb6770e4af45879e2fb1e00c742e7b52205c8015b5c0f5b1e40186ff9aa7288ab3e01a51fb87761f9bc6837082af109b39cc9f620") diff --git a/route/route.go b/route/route.go index edf6063e..bb484efd 100644 --- a/route/route.go +++ b/route/route.go @@ -622,7 +622,7 @@ func (r *Router) actionSniff( Destination: destination, } packetBuffers = append(packetBuffers, packetBuffer) - if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(packetBuffers) == 0 { + if E.IsMulti(err, sniff.ErrClientHelloFragmented) { r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello") continue } From 6cad142cfeddfc7c936fce343f6055d1584f4bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 12 Feb 2025 08:43:11 +0800 Subject: [PATCH 30/62] Bump Go to go1.24 --- .github/workflows/build.yml | 10 +++++----- .github/workflows/lint.yml | 2 +- .github/workflows/linux.yml | 2 +- Dockerfile | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 61f14cfb..217bfcfb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: Check input version if: github.event_name == 'workflow_dispatch' run: |- @@ -134,7 +134,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: Cache legacy Go if: matrix.require_legacy_go id: cache-legacy-go @@ -219,7 +219,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: Setup Android NDK id: setup-ndk uses: nttld/setup-ndk@v1 @@ -294,7 +294,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: Setup Android NDK id: setup-ndk uses: nttld/setup-ndk@v1 @@ -392,7 +392,7 @@ jobs: if: matrix.if uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: Setup Xcode stable if: matrix.if && github.ref == 'refs/heads/main-next' run: |- diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ba6a544d..3b428020 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,7 +28,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: golangci-lint uses: golangci/golangci-lint-action@v6 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 613c057a..0fec7594 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.23 + go-version: ^1.24 - name: Extract signing key run: |- mkdir -p $HOME/.gnupg diff --git a/Dockerfile b/Dockerfile index e82b81ce..6c3cfd39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.23-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder LABEL maintainer="nekohasekai " COPY . /go/src/github.com/sagernet/sing-box WORKDIR /go/src/github.com/sagernet/sing-box From 270740e8599cb8d31ddc6707761660d98b75e755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 14 Feb 2025 13:36:52 +0800 Subject: [PATCH 31/62] Fix crash on route address set update --- protocol/tun/inbound.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/protocol/tun/inbound.go b/protocol/tun/inbound.go index 3bbe0421..00cc0561 100644 --- a/protocol/tun/inbound.go +++ b/protocol/tun/inbound.go @@ -312,9 +312,11 @@ func (t *Inbound) Start(stage adapter.StartStage) error { if len(ipSets) == 0 { t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeRuleSet.Name()) } - t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet)) routeRuleSet.DecRef() t.routeAddressSet = append(t.routeAddressSet, ipSets...) + if t.autoRedirect != nil { + t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet)) + } } t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet) for _, routeExcludeRuleSet := range t.routeExcludeRuleSet { @@ -322,9 +324,11 @@ func (t *Inbound) Start(stage adapter.StartStage) error { if len(ipSets) == 0 { t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name()) } - t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet)) routeExcludeRuleSet.DecRef() t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ipSets...) + if t.autoRedirect != nil { + t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet)) + } } } var ( From 4000e1e66d448d6a765c5e169442e30700378598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 14 Feb 2025 19:13:49 +0800 Subject: [PATCH 32/62] release: Fix update android version --- .github/workflows/build.yml | 9 ++++++++- cmd/internal/update_android_version/main.go | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 217bfcfb..98316ddd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -256,9 +256,16 @@ jobs: with: path: ~/.gradle key: gradle-${{ hashFiles('**/*.gradle') }} - - name: Build + - name: Update version + if: github.event_name == 'workflow_dispatch' run: |- go run -v ./cmd/internal/update_android_version --ci + - name: Update nightly version + if: github.event_name != 'workflow_dispatch' + run: |- + go run -v ./cmd/internal/update_android_version --ci --nightly + - name: Build + run: |- mkdir clients/android/app/libs cp libbox.aar clients/android/app/libs cd clients/android diff --git a/cmd/internal/update_android_version/main.go b/cmd/internal/update_android_version/main.go index 7f27903b..4850fce0 100644 --- a/cmd/internal/update_android_version/main.go +++ b/cmd/internal/update_android_version/main.go @@ -13,10 +13,14 @@ import ( "github.com/sagernet/sing/common" ) -var flagRunInCI bool +var ( + flagRunInCI bool + flagRunNightly bool +) func init() { flag.BoolVar(&flagRunInCI, "ci", false, "Run in CI") + flag.BoolVar(&flagRunNightly, "nightly", false, "Run nightly") } func main() { @@ -61,7 +65,7 @@ func main() { if !(versionUpdated || goVersionUpdated) { log.Info("version not changed") return - } else if flagRunInCI { + } else if flagRunInCI && !flagRunNightly { log.Fatal("version changed, commit changes first.") } for _, propPair := range propsList { From 97ce666e43d8748b936bbac061844e8265820812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 18 Feb 2025 21:52:38 +0800 Subject: [PATCH 33/62] Fix http.FileServer short write --- experimental/clashapi/server.go | 2 +- experimental/clashapi/server_fs.go | 18 ++++++++++++++++++ experimental/clashapi/server_resources.go | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 experimental/clashapi/server_fs.go diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go index 2b4da4a4..efe2ce36 100644 --- a/experimental/clashapi/server.go +++ b/experimental/clashapi/server.go @@ -129,7 +129,7 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op s.externalUI = filemanager.BasePath(ctx, os.ExpandEnv(options.ExternalUI)) chiRouter.Group(func(r chi.Router) { r.Get("/ui", http.RedirectHandler("/ui/", http.StatusMovedPermanently).ServeHTTP) - r.Handle("/ui/*", http.StripPrefix("/ui/", http.FileServer(http.Dir(s.externalUI)))) + r.Handle("/ui/*", http.StripPrefix("/ui/", http.FileServer(Dir(s.externalUI)))) }) } return s, nil diff --git a/experimental/clashapi/server_fs.go b/experimental/clashapi/server_fs.go new file mode 100644 index 00000000..afb4cca5 --- /dev/null +++ b/experimental/clashapi/server_fs.go @@ -0,0 +1,18 @@ +package clashapi + +import "net/http" + +type Dir http.Dir + +func (d Dir) Open(name string) (http.File, error) { + file, err := http.Dir(d).Open(name) + if err != nil { + return nil, err + } + return &fileWrapper{file}, nil +} + +// workaround for #2345 #2596 +type fileWrapper struct { + http.File +} diff --git a/experimental/clashapi/server_resources.go b/experimental/clashapi/server_resources.go index 2e73121f..ec3b2a0f 100644 --- a/experimental/clashapi/server_resources.go +++ b/experimental/clashapi/server_resources.go @@ -41,7 +41,6 @@ func (s *Server) downloadExternalUI() error { } else { downloadURL = "https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip" } - s.logger.Info("downloading external ui") var detour adapter.Outbound if s.externalUIDownloadDetour != "" { outbound, loaded := s.outbound.Outbound(s.externalUIDownloadDetour) @@ -53,6 +52,7 @@ func (s *Server) downloadExternalUI() error { outbound := s.outbound.Default() detour = outbound } + s.logger.Info("downloading external ui using outbound/", detour.Type(), "[", detour.Tag(), "]") httpClient := &http.Client{ Transport: &http.Transport{ ForceAttemptHTTP2: true, From 93b68312cfa1f298f32aa2db06f732e59bcc160b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 20 Feb 2025 14:42:09 +0800 Subject: [PATCH 34/62] platform: Add update WIFI state func --- adapter/network.go | 1 + experimental/libbox/command_power.go | 29 ++-------------------------- experimental/libbox/service_pause.go | 4 ++++ route/network.go | 22 ++++++++++++--------- 4 files changed, 20 insertions(+), 36 deletions(-) diff --git a/adapter/network.go b/adapter/network.go index 00ef54b8..3adfaaeb 100644 --- a/adapter/network.go +++ b/adapter/network.go @@ -25,6 +25,7 @@ type NetworkManager interface { PackageManager() tun.PackageManager WIFIState() WIFIState ResetNetwork() + UpdateWIFIState() } type NetworkOptions struct { diff --git a/experimental/libbox/command_power.go b/experimental/libbox/command_power.go index 5ed7b014..00906490 100644 --- a/experimental/libbox/command_power.go +++ b/experimental/libbox/command_power.go @@ -4,7 +4,6 @@ import ( "encoding/binary" "net" - E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/varbin" ) @@ -18,19 +17,7 @@ func (c *CommandClient) ServiceReload() error { if err != nil { return err } - var hasError bool - err = binary.Read(conn, binary.BigEndian, &hasError) - if err != nil { - return err - } - if hasError { - errorMessage, err := varbin.ReadValue[string](conn, binary.BigEndian) - if err != nil { - return err - } - return E.New(errorMessage) - } - return nil + return readError(conn) } func (s *CommandServer) handleServiceReload(conn net.Conn) error { @@ -55,19 +42,7 @@ func (c *CommandClient) ServiceClose() error { if err != nil { return err } - var hasError bool - err = binary.Read(conn, binary.BigEndian, &hasError) - if err != nil { - return nil - } - if hasError { - errorMessage, err := varbin.ReadValue[string](conn, binary.BigEndian) - if err != nil { - return nil - } - return E.New(errorMessage) - } - return nil + return readError(conn) } func (s *CommandServer) handleServiceClose(conn net.Conn) error { diff --git a/experimental/libbox/service_pause.go b/experimental/libbox/service_pause.go index a7599a76..0fa9541f 100644 --- a/experimental/libbox/service_pause.go +++ b/experimental/libbox/service_pause.go @@ -31,3 +31,7 @@ func (s *BoxService) Wake() { func (s *BoxService) ResetNetwork() { s.instance.Router().ResetNetwork() } + +func (s *BoxService) UpdateWIFIState() { + s.instance.Network().UpdateWIFIState() +} diff --git a/route/network.go b/route/network.go index 97d165f1..ab1be76c 100644 --- a/route/network.go +++ b/route/network.go @@ -354,6 +354,18 @@ func (r *NetworkManager) WIFIState() adapter.WIFIState { return r.wifiState } +func (r *NetworkManager) UpdateWIFIState() { + if r.platformInterface != nil { + state := r.platformInterface.ReadWIFIState() + if state != r.wifiState { + r.wifiState = state + if state.SSID != "" { + r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID) + } + } + } +} + func (r *NetworkManager) ResetNetwork() { conntrack.Close() @@ -414,15 +426,7 @@ func (r *NetworkManager) notifyInterfaceUpdate(defaultInterface *control.Interfa } } r.logger.Info("updated default interface ", defaultInterface.Name, ", ", strings.Join(options, ", ")) - if r.platformInterface != nil { - state := r.platformInterface.ReadWIFIState() - if state != r.wifiState { - r.wifiState = state - if state.SSID != "" { - r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID) - } - } - } + r.UpdateWIFIState() if !r.started { return From 7eb353509495c8691690cbd9ee81144871090a8e Mon Sep 17 00:00:00 2001 From: Gavin Luo Date: Thu, 20 Feb 2025 17:57:09 +0800 Subject: [PATCH 35/62] release: Fix systemd permissions --- release/config/sing-box.service | 4 ++-- release/config/sing-box@.service | 4 ++-- release/local/sing-box.service | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/release/config/sing-box.service b/release/config/sing-box.service index 7b7a13a8..388d7250 100644 --- a/release/config/sing-box.service +++ b/release/config/sing-box.service @@ -4,8 +4,8 @@ Documentation=https://sing-box.sagernet.org After=network.target nss-lookup.target network-online.target [Service] -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH ExecStart=/usr/bin/sing-box -D /var/lib/sing-box -C /etc/sing-box run ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure diff --git a/release/config/sing-box@.service b/release/config/sing-box@.service index 578ebd1c..38866457 100644 --- a/release/config/sing-box@.service +++ b/release/config/sing-box@.service @@ -4,8 +4,8 @@ Documentation=https://sing-box.sagernet.org After=network.target nss-lookup.target network-online.target [Service] -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH ExecStart=/usr/bin/sing-box -D /var/lib/sing-box-%i -c /etc/sing-box/%i.json run ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure diff --git a/release/local/sing-box.service b/release/local/sing-box.service index 7dfd6f79..9a152ade 100644 --- a/release/local/sing-box.service +++ b/release/local/sing-box.service @@ -4,8 +4,8 @@ Documentation=https://sing-box.sagernet.org After=network.target nss-lookup.target network-online.target [Service] -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH ExecStart=/usr/local/bin/sing-box -D /var/lib/sing-box -C /usr/local/etc/sing-box run ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure From eb07c7a79eeca943370eafea601e87da76c0e57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 23 Feb 2025 08:36:57 +0800 Subject: [PATCH 36/62] Bump version --- clients/android | 2 +- clients/apple | 2 +- docs/changelog.md | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/android b/clients/android index 3a2fc9c8..0576fd75 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit 3a2fc9c8802f0c40f0b1fd2d7acdcabb7aa0855f +Subproject commit 0576fd75a67e56048c29d00ef539b4f8f05aec2a diff --git a/clients/apple b/clients/apple index 3d5d7343..a828bb3a 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit 3d5d7343fb473dce772633183791524629493213 +Subproject commit a828bb3a93b57d0c1b13d74246f0675c5244466d diff --git a/docs/changelog.md b/docs/changelog.md index c1d7ba89..cf40c0ed 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,10 @@ icon: material/alert-decagram --- +### 1.11.4 + +* Fixes and improvements + ### 1.11.3 * Fixes and improvements From 777066572fe6a3d9a6e7b6ce56aa1b6f5cb8a794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 2 Dec 2024 23:17:01 +0800 Subject: [PATCH 37/62] refactor: DNS --- .goreleaser.fury.yaml | 4 +- adapter/dns.go | 73 +++ adapter/experimental.go | 3 +- adapter/fakeip.go | 3 +- adapter/inbound.go | 2 - adapter/outbound/manager.go | 17 +- adapter/router.go | 17 - adapter/rule.go | 1 - box.go | 113 +++- cmd/sing-box/cmd.go | 2 +- common/dialer/dialer.go | 9 +- common/dialer/resolve.go | 60 +- common/dialer/router.go | 15 +- common/tls/ech_client.go | 4 +- common/tls/std_client.go | 5 +- constant/dns.go | 29 + dns/client.go | 563 ++++++++++++++++++ dns/client_log.go | 69 +++ dns/client_truncate.go | 29 + dns/extension_edns0_subnet.go | 56 ++ dns/rcode.go | 33 + dns/router.go | 437 ++++++++++++++ .../server.go => dns/transport/dhcp/dhcp.go | 135 ++--- dns/transport/fakeip/fakeip.go | 67 +++ {transport => dns/transport}/fakeip/memory.go | 0 {transport => dns/transport}/fakeip/store.go | 0 dns/transport/hosts/hosts.go | 63 ++ dns/transport/hosts/hosts_file.go | 102 ++++ dns/transport/hosts/hosts_test.go | 16 + dns/transport/hosts/hosts_unix.go | 5 + dns/transport/hosts/hosts_windows.go | 17 + dns/transport/hosts/testdata/hosts | 2 + dns/transport/https.go | 204 +++++++ dns/transport/local/local.go | 197 ++++++ dns/transport/local/resolv.go | 146 +++++ dns/transport/local/resolv_unix.go | 175 ++++++ dns/transport/local/resolv_windows.go | 100 ++++ dns/transport/predefined.go | 83 +++ dns/transport/quic/http3.go | 167 ++++++ dns/transport/quic/quic.go | 174 ++++++ dns/transport/tcp.go | 99 +++ dns/transport/tls.go | 115 ++++ dns/transport/udp.go | 223 +++++++ dns/transport_adapter.go | 70 +++ dns/transport_dialer.go | 93 +++ dns/transport_manager.go | 288 +++++++++ dns/transport_registry.go | 72 +++ experimental/clashapi/dns.go | 6 +- experimental/clashapi/server.go | 16 +- experimental/deprecated/constants.go | 15 + experimental/libbox/config.go | 19 +- experimental/libbox/dns.go | 161 ++--- experimental/libbox/platform.go | 1 + experimental/libbox/service.go | 6 +- go.mod | 1 - go.sum | 2 - include/dhcp.go | 9 +- include/dhcp_stub.go | 12 +- include/quic.go | 8 +- include/quic_stub.go | 14 +- include/registry.go | 27 +- option/dns.go | 315 +++++++++- option/dns_record.go | 161 +++++ option/rule_action.go | 13 +- option/rule_dns.go | 1 + option/types.go | 37 +- protocol/direct/outbound.go | 29 +- protocol/dns/handle.go | 14 +- protocol/dns/outbound.go | 5 +- protocol/socks/outbound.go | 17 +- protocol/wireguard/endpoint.go | 12 +- protocol/wireguard/outbound.go | 14 +- release/config/config.json | 9 +- route/dns.go | 27 +- route/geo_resources.go | 246 -------- route/route.go | 46 +- route/route_dns.go | 348 ----------- route/router.go | 414 ++----------- route/rule/rule_abstract.go | 25 - route/rule/rule_action.go | 14 +- route/rule/rule_default.go | 12 +- route/rule/rule_dns.go | 17 +- route/rule/rule_item_geoip.go | 98 --- route/rule/rule_item_geosite.go | 61 -- route/rule/rule_item_ip_accept_any.go | 21 + route/rule_conds.go | 21 - test/domain_inbound_test.go | 3 +- transport/fakeip/server.go | 95 --- transport/v2rayhttp/server.go | 2 +- 89 files changed, 4796 insertions(+), 1735 deletions(-) create mode 100644 adapter/dns.go create mode 100644 dns/client.go create mode 100644 dns/client_log.go create mode 100644 dns/client_truncate.go create mode 100644 dns/extension_edns0_subnet.go create mode 100644 dns/rcode.go create mode 100644 dns/router.go rename transport/dhcp/server.go => dns/transport/dhcp/dhcp.go (66%) create mode 100644 dns/transport/fakeip/fakeip.go rename {transport => dns/transport}/fakeip/memory.go (100%) rename {transport => dns/transport}/fakeip/store.go (100%) create mode 100644 dns/transport/hosts/hosts.go create mode 100644 dns/transport/hosts/hosts_file.go create mode 100644 dns/transport/hosts/hosts_test.go create mode 100644 dns/transport/hosts/hosts_unix.go create mode 100644 dns/transport/hosts/hosts_windows.go create mode 100644 dns/transport/hosts/testdata/hosts create mode 100644 dns/transport/https.go create mode 100644 dns/transport/local/local.go create mode 100644 dns/transport/local/resolv.go create mode 100644 dns/transport/local/resolv_unix.go create mode 100644 dns/transport/local/resolv_windows.go create mode 100644 dns/transport/predefined.go create mode 100644 dns/transport/quic/http3.go create mode 100644 dns/transport/quic/quic.go create mode 100644 dns/transport/tcp.go create mode 100644 dns/transport/tls.go create mode 100644 dns/transport/udp.go create mode 100644 dns/transport_adapter.go create mode 100644 dns/transport_dialer.go create mode 100644 dns/transport_manager.go create mode 100644 dns/transport_registry.go create mode 100644 option/dns_record.go delete mode 100644 route/geo_resources.go delete mode 100644 route/route_dns.go delete mode 100644 route/rule/rule_item_geoip.go delete mode 100644 route/rule/rule_item_geosite.go create mode 100644 route/rule/rule_item_ip_accept_any.go delete mode 100644 transport/fakeip/server.go diff --git a/.goreleaser.fury.yaml b/.goreleaser.fury.yaml index fbd1ae42..d80dd408 100644 --- a/.goreleaser.fury.yaml +++ b/.goreleaser.fury.yaml @@ -6,7 +6,9 @@ builds: - -v - -trimpath ldflags: - - -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid= + - -X github.com/sagernet/sing-box/constant.Version={{ .Version }} + - -s + - -buildid= tags: - with_gvisor - with_quic diff --git a/adapter/dns.go b/adapter/dns.go new file mode 100644 index 00000000..e0f381b8 --- /dev/null +++ b/adapter/dns.go @@ -0,0 +1,73 @@ +package adapter + +import ( + "context" + "net/netip" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common/logger" + + "github.com/miekg/dns" +) + +type DNSRouter interface { + Lifecycle + Exchange(ctx context.Context, message *dns.Msg, options DNSQueryOptions) (*dns.Msg, error) + Lookup(ctx context.Context, domain string, options DNSQueryOptions) ([]netip.Addr, error) + ClearCache() + LookupReverseMapping(ip netip.Addr) (string, bool) + ResetNetwork() +} + +type DNSClient interface { + Start() + Exchange(ctx context.Context, transport DNSTransport, message *dns.Msg, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error) + Lookup(ctx context.Context, transport DNSTransport, domain string, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error) + LookupCache(domain string, strategy C.DomainStrategy) ([]netip.Addr, bool) + ExchangeCache(ctx context.Context, message *dns.Msg) (*dns.Msg, bool) + ClearCache() +} + +type DNSQueryOptions struct { + Transport DNSTransport + Strategy C.DomainStrategy + DisableCache bool + RewriteTTL *uint32 + ClientSubnet netip.Prefix +} + +type RDRCStore interface { + LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) + SaveRDRC(transportName string, qName string, qType uint16) error + SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) +} + +type DNSTransport interface { + Type() string + Tag() string + Dependencies() []string + Reset() + Exchange(ctx context.Context, message *dns.Msg) (*dns.Msg, error) +} + +type LegacyDNSTransport interface { + LegacyStrategy() C.DomainStrategy + LegacyClientSubnet() netip.Prefix +} + +type DNSTransportRegistry interface { + option.DNSTransportOptionsRegistry + CreateDNSTransport(ctx context.Context, logger log.ContextLogger, tag string, transportType string, options any) (DNSTransport, error) +} + +type DNSTransportManager interface { + Lifecycle + Transports() []DNSTransport + Transport(tag string) (DNSTransport, bool) + Default() DNSTransport + FakeIP() FakeIPTransport + Remove(tag string) error + Create(ctx context.Context, logger log.ContextLogger, tag string, outboundType string, options any) error +} diff --git a/adapter/experimental.go b/adapter/experimental.go index 648eb418..99d7c9a5 100644 --- a/adapter/experimental.go +++ b/adapter/experimental.go @@ -7,7 +7,6 @@ import ( "time" "github.com/sagernet/sing-box/common/urltest" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common/varbin" ) @@ -31,7 +30,7 @@ type CacheFile interface { FakeIPStorage StoreRDRC() bool - dns.RDRCStore + RDRCStore LoadMode() string StoreMode(mode string) error diff --git a/adapter/fakeip.go b/adapter/fakeip.go index 51247c32..97d1c3c0 100644 --- a/adapter/fakeip.go +++ b/adapter/fakeip.go @@ -3,7 +3,6 @@ package adapter import ( "net/netip" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common/logger" ) @@ -27,6 +26,6 @@ type FakeIPStorage interface { } type FakeIPTransport interface { - dns.Transport + DNSTransport Store() FakeIPStore } diff --git a/adapter/inbound.go b/adapter/inbound.go index 93d2ec60..f70066f5 100644 --- a/adapter/inbound.go +++ b/adapter/inbound.go @@ -77,8 +77,6 @@ type InboundContext struct { FallbackNetworkType []C.InterfaceType FallbackDelay time.Duration - DNSServer string - DestinationAddresses []netip.Addr SourceGeoIPCode string GeoIPCode string diff --git a/adapter/outbound/manager.go b/adapter/outbound/manager.go index c3941d02..977fe4ca 100644 --- a/adapter/outbound/manager.go +++ b/adapter/outbound/manager.go @@ -23,7 +23,7 @@ type Manager struct { registry adapter.OutboundRegistry endpoint adapter.EndpointManager defaultTag string - access sync.Mutex + access sync.RWMutex started bool stage adapter.StartStage outbounds []adapter.Outbound @@ -169,15 +169,15 @@ func (m *Manager) Close() error { } func (m *Manager) Outbounds() []adapter.Outbound { - m.access.Lock() - defer m.access.Unlock() + m.access.RLock() + defer m.access.RUnlock() return m.outbounds } func (m *Manager) Outbound(tag string) (adapter.Outbound, bool) { - m.access.Lock() + m.access.RLock() outbound, found := m.outboundByTag[tag] - m.access.Unlock() + m.access.RUnlock() if found { return outbound, true } @@ -185,8 +185,8 @@ func (m *Manager) Outbound(tag string) (adapter.Outbound, bool) { } func (m *Manager) Default() adapter.Outbound { - m.access.Lock() - defer m.access.Unlock() + m.access.RLock() + defer m.access.RUnlock() if m.defaultOutbound != nil { return m.defaultOutbound } else { @@ -196,9 +196,9 @@ func (m *Manager) Default() adapter.Outbound { func (m *Manager) Remove(tag string) error { m.access.Lock() + defer m.access.Unlock() outbound, found := m.outboundByTag[tag] if !found { - m.access.Unlock() return os.ErrInvalid } delete(m.outboundByTag, tag) @@ -232,7 +232,6 @@ func (m *Manager) Remove(tag string) error { }) } } - m.access.Unlock() if started { return common.Close(outbound) } diff --git a/adapter/router.go b/adapter/router.go index a637e506..9cefb49d 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -4,42 +4,25 @@ import ( "context" "net" "net/http" - "net/netip" "sync" - "github.com/sagernet/sing-box/common/geoip" C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-dns" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/x/list" - mdns "github.com/miekg/dns" "go4.org/netipx" ) type Router interface { Lifecycle - - FakeIPStore() FakeIPStore - ConnectionRouter PreMatch(metadata InboundContext) error ConnectionRouterEx - - GeoIPReader() *geoip.Reader - LoadGeosite(code string) (Rule, error) RuleSet(tag string) (RuleSet, bool) NeedWIFIState() bool - - Exchange(ctx context.Context, message *mdns.Msg) (*mdns.Msg, error) - Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) - LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error) - ClearDNSCache() Rules() []Rule - SetTracker(tracker ConnectionTracker) - ResetNetwork() } diff --git a/adapter/rule.go b/adapter/rule.go index f3737a25..2512a77b 100644 --- a/adapter/rule.go +++ b/adapter/rule.go @@ -13,7 +13,6 @@ type Rule interface { HeadlessRule Service Type() string - UpdateGeosite() error Action() RuleAction } diff --git a/box.go b/box.go index 0cbf1b3b..bd15c66a 100644 --- a/box.go +++ b/box.go @@ -16,6 +16,8 @@ import ( "github.com/sagernet/sing-box/common/taskmonitor" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport/local" "github.com/sagernet/sing-box/experimental" "github.com/sagernet/sing-box/experimental/cachefile" "github.com/sagernet/sing-box/experimental/libbox/platform" @@ -34,17 +36,19 @@ import ( var _ adapter.Service = (*Box)(nil) type Box struct { - createdAt time.Time - logFactory log.Factory - logger log.ContextLogger - network *route.NetworkManager - endpoint *endpoint.Manager - inbound *inbound.Manager - outbound *outbound.Manager - connection *route.ConnectionManager - router *route.Router - services []adapter.LifecycleService - done chan struct{} + createdAt time.Time + logFactory log.Factory + logger log.ContextLogger + network *route.NetworkManager + endpoint *endpoint.Manager + inbound *inbound.Manager + outbound *outbound.Manager + dnsTransport *dns.TransportManager + dnsRouter *dns.Router + connection *route.ConnectionManager + router *route.Router + services []adapter.LifecycleService + done chan struct{} } type Options struct { @@ -58,6 +62,7 @@ func Context( inboundRegistry adapter.InboundRegistry, outboundRegistry adapter.OutboundRegistry, endpointRegistry adapter.EndpointRegistry, + dnsTransportRegistry adapter.DNSTransportRegistry, ) context.Context { if service.FromContext[option.InboundOptionsRegistry](ctx) == nil || service.FromContext[adapter.InboundRegistry](ctx) == nil { @@ -74,6 +79,10 @@ func Context( ctx = service.ContextWith[option.EndpointOptionsRegistry](ctx, endpointRegistry) ctx = service.ContextWith[adapter.EndpointRegistry](ctx, endpointRegistry) } + if service.FromContext[adapter.DNSTransportRegistry](ctx) == nil { + ctx = service.ContextWith[option.DNSTransportOptionsRegistry](ctx, dnsTransportRegistry) + ctx = service.ContextWith[adapter.DNSTransportRegistry](ctx, dnsTransportRegistry) + } return ctx } @@ -88,6 +97,7 @@ func New(options Options) (*Box, error) { endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx) inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx) outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx) + dnsTransportRegistry := service.FromContext[adapter.DNSTransportRegistry](ctx) if endpointRegistry == nil { return nil, E.New("missing endpoint registry in context") @@ -132,13 +142,17 @@ func New(options Options) (*Box, error) { } routeOptions := common.PtrValueOrDefault(options.Route) + dnsOptions := common.PtrValueOrDefault(options.DNS) endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry) inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager) outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final) + dnsTransportManager := dns.NewTransportManager(logFactory.NewLogger("dns/transport"), dnsTransportRegistry, outboundManager, dnsOptions.Final) service.MustRegister[adapter.EndpointManager](ctx, endpointManager) service.MustRegister[adapter.InboundManager](ctx, inboundManager) service.MustRegister[adapter.OutboundManager](ctx, outboundManager) - + service.MustRegister[adapter.DNSTransportManager](ctx, dnsTransportManager) + dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions) + service.MustRegister[adapter.DNSRouter](ctx, dnsRouter) networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions) if err != nil { return nil, E.Cause(err, "initialize network manager") @@ -146,18 +160,40 @@ func New(options Options) (*Box, error) { service.MustRegister[adapter.NetworkManager](ctx, networkManager) connectionManager := route.NewConnectionManager(logFactory.NewLogger("connection")) service.MustRegister[adapter.ConnectionManager](ctx, connectionManager) - router, err := route.NewRouter(ctx, logFactory, routeOptions, common.PtrValueOrDefault(options.DNS)) + router := route.NewRouter(ctx, logFactory, routeOptions, dnsOptions) + service.MustRegister[adapter.Router](ctx, router) + err = router.Initialize(routeOptions.Rules, routeOptions.RuleSet) if err != nil { return nil, E.Cause(err, "initialize router") } - ntpOptions := common.PtrValueOrDefault(options.NTP) var timeService *tls.TimeServiceWrapper if ntpOptions.Enabled { timeService = new(tls.TimeServiceWrapper) service.MustRegister[ntp.TimeService](ctx, timeService) } - + for i, transportOptions := range dnsOptions.Servers { + var tag string + if transportOptions.Tag != "" { + tag = transportOptions.Tag + } else { + tag = F.ToString(i) + } + err = dnsTransportManager.Create( + ctx, + logFactory.NewLogger(F.ToString("dns/", transportOptions.Type, "[", tag, "]")), + tag, + transportOptions.Type, + transportOptions.Options, + ) + if err != nil { + return nil, E.Cause(err, "initialize inbound[", i, "]") + } + } + err = dnsRouter.Initialize(dnsOptions.Rules) + if err != nil { + return nil, E.Cause(err, "initialize dns router") + } for i, endpointOptions := range options.Endpoints { var tag string if endpointOptions.Tag != "" { @@ -165,7 +201,8 @@ func New(options Options) (*Box, error) { } else { tag = F.ToString(i) } - err = endpointManager.Create(ctx, + err = endpointManager.Create( + ctx, router, logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")), tag, @@ -183,7 +220,8 @@ func New(options Options) (*Box, error) { } else { tag = F.ToString(i) } - err = inboundManager.Create(ctx, + err = inboundManager.Create( + ctx, router, logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")), tag, @@ -229,6 +267,13 @@ func New(options Options) (*Box, error) { option.DirectOutboundOptions{}, ), )) + dnsTransportManager.Initialize(common.Must1( + local.NewTransport( + ctx, + logFactory.NewLogger("dns/local"), + "local", + option.LocalDNSServerOptions{}, + ))) if platformInterface != nil { err = platformInterface.Initialize(networkManager) if err != nil { @@ -280,17 +325,19 @@ func New(options Options) (*Box, error) { services = append(services, adapter.NewLifecycleService(ntpService, "ntp service")) } return &Box{ - network: networkManager, - endpoint: endpointManager, - inbound: inboundManager, - outbound: outboundManager, - connection: connectionManager, - router: router, - createdAt: createdAt, - logFactory: logFactory, - logger: logFactory.Logger(), - services: services, - done: make(chan struct{}), + network: networkManager, + endpoint: endpointManager, + inbound: inboundManager, + outbound: outboundManager, + dnsTransport: dnsTransportManager, + dnsRouter: dnsRouter, + connection: connectionManager, + router: router, + createdAt: createdAt, + logFactory: logFactory, + logger: logFactory.Logger(), + services: services, + done: make(chan struct{}), }, nil } @@ -344,11 +391,11 @@ func (s *Box) preStart() error { if err != nil { return err } - err = adapter.Start(adapter.StartStateInitialize, s.network, s.connection, s.router, s.outbound, s.inbound, s.endpoint) + err = adapter.Start(adapter.StartStateInitialize, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint) if err != nil { return err } - err = adapter.Start(adapter.StartStateStart, s.outbound, s.network, s.connection, s.router) + err = adapter.Start(adapter.StartStateStart, s.outbound, s.dnsTransport, s.dnsRouter, s.network, s.connection, s.router) if err != nil { return err } @@ -372,7 +419,7 @@ func (s *Box) start() error { if err != nil { return err } - err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.connection, s.router, s.inbound, s.endpoint) + err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.inbound, s.endpoint) if err != nil { return err } @@ -380,7 +427,7 @@ func (s *Box) start() error { if err != nil { return err } - err = adapter.Start(adapter.StartStateStarted, s.network, s.connection, s.router, s.outbound, s.inbound, s.endpoint) + err = adapter.Start(adapter.StartStateStarted, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint) if err != nil { return err } @@ -399,7 +446,7 @@ func (s *Box) Close() error { close(s.done) } err := common.Close( - s.inbound, s.outbound, s.endpoint, s.router, s.connection, s.network, + s.inbound, s.outbound, s.endpoint, s.router, s.connection, s.dnsRouter, s.dnsTransport, s.network, ) for _, lifecycleService := range s.services { err = E.Append(err, lifecycleService.Close(), func(err error) error { diff --git a/cmd/sing-box/cmd.go b/cmd/sing-box/cmd.go index d55235b8..55fe1179 100644 --- a/cmd/sing-box/cmd.go +++ b/cmd/sing-box/cmd.go @@ -69,5 +69,5 @@ func preRun(cmd *cobra.Command, args []string) { configPaths = append(configPaths, "config.json") } globalCtx = service.ContextWith(globalCtx, deprecated.NewStderrManager(log.StdLogger())) - globalCtx = box.Context(globalCtx, include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()) + globalCtx = box.Context(globalCtx, include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), include.DNSTransportRegistry()) } diff --git a/common/dialer/dialer.go b/common/dialer/dialer.go index 89d1eeab..f63e3864 100644 --- a/common/dialer/dialer.go +++ b/common/dialer/dialer.go @@ -9,7 +9,6 @@ import ( "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-dns" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" @@ -37,13 +36,13 @@ func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) { dialer = NewDetour(outboundManager, options.Detour) } if options.Detour == "" { - router := service.FromContext[adapter.Router](ctx) + router := service.FromContext[adapter.DNSRouter](ctx) if router != nil { dialer = NewResolveDialer( router, dialer, options.Detour == "" && !options.TCPFastOpen, - dns.DomainStrategy(options.DomainStrategy), + C.DomainStrategy(options.DomainStrategy), time.Duration(options.FallbackDelay)) } } @@ -62,10 +61,10 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter return nil, err } return NewResolveParallelInterfaceDialer( - service.FromContext[adapter.Router](ctx), + service.FromContext[adapter.DNSRouter](ctx), dialer, true, - dns.DomainStrategy(options.DomainStrategy), + C.DomainStrategy(options.DomainStrategy), time.Duration(options.FallbackDelay), ), nil } diff --git a/common/dialer/resolve.go b/common/dialer/resolve.go index ede1afd6..3d667a6c 100644 --- a/common/dialer/resolve.go +++ b/common/dialer/resolve.go @@ -3,13 +3,11 @@ package dialer import ( "context" "net" - "net/netip" "time" "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" @@ -23,12 +21,12 @@ var ( type resolveDialer struct { dialer N.Dialer parallel bool - router adapter.Router - strategy dns.DomainStrategy + router adapter.DNSRouter + strategy C.DomainStrategy fallbackDelay time.Duration } -func NewResolveDialer(router adapter.Router, dialer N.Dialer, parallel bool, strategy dns.DomainStrategy, fallbackDelay time.Duration) N.Dialer { +func NewResolveDialer(router adapter.DNSRouter, dialer N.Dialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer { return &resolveDialer{ dialer, parallel, @@ -43,7 +41,7 @@ type resolveParallelNetworkDialer struct { dialer ParallelInterfaceDialer } -func NewResolveParallelInterfaceDialer(router adapter.Router, dialer ParallelInterfaceDialer, parallel bool, strategy dns.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer { +func NewResolveParallelInterfaceDialer(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer { return &resolveParallelNetworkDialer{ resolveDialer{ dialer, @@ -60,22 +58,13 @@ func (d *resolveDialer) DialContext(ctx context.Context, network string, destina if !destination.IsFqdn() { return d.dialer.DialContext(ctx, network, destination) } - ctx, metadata := adapter.ExtendContext(ctx) ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - metadata.Destination = destination - metadata.Domain = "" - var addresses []netip.Addr - var err error - if d.strategy == dns.DomainStrategyAsIS { - addresses, err = d.router.LookupDefault(ctx, destination.Fqdn) - } else { - addresses, err = d.router.Lookup(ctx, destination.Fqdn, d.strategy) - } + addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy}) if err != nil { return nil, err } if d.parallel { - return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == dns.DomainStrategyPreferIPv6, d.fallbackDelay) + return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay) } else { return N.DialSerial(ctx, d.dialer, network, destination, addresses) } @@ -85,17 +74,8 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd if !destination.IsFqdn() { return d.dialer.ListenPacket(ctx, destination) } - ctx, metadata := adapter.ExtendContext(ctx) ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - metadata.Destination = destination - metadata.Domain = "" - var addresses []netip.Addr - var err error - if d.strategy == dns.DomainStrategyAsIS { - addresses, err = d.router.LookupDefault(ctx, destination.Fqdn) - } else { - addresses, err = d.router.Lookup(ctx, destination.Fqdn, d.strategy) - } + addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy}) if err != nil { return nil, err } @@ -110,17 +90,10 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context if !destination.IsFqdn() { return d.dialer.DialContext(ctx, network, destination) } - ctx, metadata := adapter.ExtendContext(ctx) ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - metadata.Destination = destination - metadata.Domain = "" - var addresses []netip.Addr - var err error - if d.strategy == dns.DomainStrategyAsIS { - addresses, err = d.router.LookupDefault(ctx, destination.Fqdn) - } else { - addresses, err = d.router.Lookup(ctx, destination.Fqdn, d.strategy) - } + addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{ + Strategy: d.strategy, + }) if err != nil { return nil, err } @@ -128,7 +101,7 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context fallbackDelay = d.fallbackDelay } if d.parallel { - return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == dns.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) + return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) } else { return DialSerialNetwork(ctx, d.dialer, network, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) } @@ -138,17 +111,8 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C if !destination.IsFqdn() { return d.dialer.ListenPacket(ctx, destination) } - ctx, metadata := adapter.ExtendContext(ctx) ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - metadata.Destination = destination - metadata.Domain = "" - var addresses []netip.Addr - var err error - if d.strategy == dns.DomainStrategyAsIS { - addresses, err = d.router.LookupDefault(ctx, destination.Fqdn) - } else { - addresses, err = d.router.Lookup(ctx, destination.Fqdn, d.strategy) - } + addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy}) if err != nil { return nil, err } diff --git a/common/dialer/router.go b/common/dialer/router.go index 3edce65b..801a36b1 100644 --- a/common/dialer/router.go +++ b/common/dialer/router.go @@ -7,24 +7,27 @@ import ( "github.com/sagernet/sing-box/adapter" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" ) type DefaultOutboundDialer struct { - outboundManager adapter.OutboundManager + outbound adapter.OutboundManager } -func NewDefaultOutbound(outboundManager adapter.OutboundManager) N.Dialer { - return &DefaultOutboundDialer{outboundManager: outboundManager} +func NewDefaultOutbound(ctx context.Context) N.Dialer { + return &DefaultOutboundDialer{ + outbound: service.FromContext[adapter.OutboundManager](ctx), + } } func (d *DefaultOutboundDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - return d.outboundManager.Default().DialContext(ctx, network, destination) + return d.outbound.Default().DialContext(ctx, network, destination) } func (d *DefaultOutboundDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return d.outboundManager.Default().ListenPacket(ctx, destination) + return d.outbound.Default().ListenPacket(ctx, destination) } func (d *DefaultOutboundDialer) Upstream() any { - return d.outboundManager.Default() + return d.outbound.Default() } diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index 0ae3997a..fff1873d 100644 --- a/common/tls/ech_client.go +++ b/common/tls/ech_client.go @@ -15,8 +15,8 @@ import ( cftls "github.com/sagernet/cloudflare-tls" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-dns" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/ntp" "github.com/sagernet/sing/service" @@ -215,7 +215,7 @@ func fetchECHClientConfig(ctx context.Context) func(_ context.Context, serverNam }, }, } - response, err := service.FromContext[adapter.Router](ctx).Exchange(ctx, message) + response, err := service.FromContext[adapter.DNSRouter](ctx).Exchange(ctx, message, adapter.DNSQueryOptions{}) if err != nil { return nil, err } diff --git a/common/tls/std_client.go b/common/tls/std_client.go index 90f51821..7cd130a6 100644 --- a/common/tls/std_client.go +++ b/common/tls/std_client.go @@ -5,7 +5,6 @@ import ( "crypto/tls" "crypto/x509" "net" - "net/netip" "os" "strings" @@ -51,9 +50,7 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb if options.ServerName != "" { serverName = options.ServerName } else if serverAddress != "" { - if _, err := netip.ParseAddr(serverName); err != nil { - serverName = serverAddress - } + serverName = serverAddress } if serverName == "" && !options.Insecure { return nil, E.New("missing server_name or insecure=true") diff --git a/constant/dns.go b/constant/dns.go index 3907b8c1..99461a27 100644 --- a/constant/dns.go +++ b/constant/dns.go @@ -1,5 +1,34 @@ package constant +const ( + DefaultDNSTTL = 600 +) + +type DomainStrategy = uint8 + +const ( + DomainStrategyAsIS DomainStrategy = iota + DomainStrategyPreferIPv4 + DomainStrategyPreferIPv6 + DomainStrategyIPv4Only + DomainStrategyIPv6Only +) + +const ( + DNSTypeLegacy = "legacy" + DNSTypeUDP = "udp" + DNSTypeTCP = "tcp" + DNSTypeTLS = "tls" + DNSTypeHTTPS = "https" + DNSTypeQUIC = "quic" + DNSTypeHTTP3 = "h3" + DNSTypeHosts = "hosts" + DNSTypeLocal = "local" + DNSTypePreDefined = "predefined" + DNSTypeFakeIP = "fakeip" + DNSTypeDHCP = "dhcp" +) + const ( DNSProviderAliDNS = "alidns" DNSProviderCloudflare = "cloudflare" diff --git a/dns/client.go b/dns/client.go new file mode 100644 index 00000000..79b6fce5 --- /dev/null +++ b/dns/client.go @@ -0,0 +1,563 @@ +package dns + +import ( + "context" + "net" + "net/netip" + "strings" + "time" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/task" + "github.com/sagernet/sing/contrab/freelru" + "github.com/sagernet/sing/contrab/maphash" + + "github.com/miekg/dns" +) + +var ( + ErrNoRawSupport = E.New("no raw query support by current transport") + ErrNotCached = E.New("not cached") + ErrResponseRejected = E.New("response rejected") + ErrResponseRejectedCached = E.Extend(ErrResponseRejected, "cached") +) + +var _ adapter.DNSClient = (*Client)(nil) + +type Client struct { + timeout time.Duration + disableCache bool + disableExpire bool + independentCache bool + rdrc adapter.RDRCStore + initRDRCFunc func() adapter.RDRCStore + logger logger.ContextLogger + cache freelru.Cache[dns.Question, *dns.Msg] + transportCache freelru.Cache[transportCacheKey, *dns.Msg] +} + +type ClientOptions struct { + Timeout time.Duration + DisableCache bool + DisableExpire bool + IndependentCache bool + CacheCapacity uint32 + RDRC func() adapter.RDRCStore + Logger logger.ContextLogger +} + +func NewClient(options ClientOptions) *Client { + client := &Client{ + timeout: options.Timeout, + disableCache: options.DisableCache, + disableExpire: options.DisableExpire, + independentCache: options.IndependentCache, + initRDRCFunc: options.RDRC, + logger: options.Logger, + } + if client.timeout == 0 { + client.timeout = C.DNSTimeout + } + cacheCapacity := options.CacheCapacity + if cacheCapacity < 1024 { + cacheCapacity = 1024 + } + if !client.disableCache { + if !client.independentCache { + client.cache = common.Must1(freelru.NewSharded[dns.Question, *dns.Msg](cacheCapacity, maphash.NewHasher[dns.Question]().Hash32)) + } else { + client.transportCache = common.Must1(freelru.NewSharded[transportCacheKey, *dns.Msg](cacheCapacity, maphash.NewHasher[transportCacheKey]().Hash32)) + } + } + return client +} + +type transportCacheKey struct { + dns.Question + transportTag string +} + +func (c *Client) Start() { + if c.initRDRCFunc != nil { + c.rdrc = c.initRDRCFunc() + } +} + +func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error) { + if len(message.Question) == 0 { + if c.logger != nil { + c.logger.WarnContext(ctx, "bad question size: ", len(message.Question)) + } + responseMessage := dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: message.Id, + Response: true, + Rcode: dns.RcodeFormatError, + }, + Question: message.Question, + } + return &responseMessage, nil + } + question := message.Question[0] + if options.ClientSubnet.IsValid() { + message = SetClientSubnet(message, options.ClientSubnet, true) + } + isSimpleRequest := len(message.Question) == 1 && + len(message.Ns) == 0 && + len(message.Extra) == 0 && + !options.ClientSubnet.IsValid() + disableCache := !isSimpleRequest || c.disableCache || options.DisableCache + if !disableCache { + response, ttl := c.loadResponse(question, transport) + if response != nil { + logCachedResponse(c.logger, ctx, response, ttl) + response.Id = message.Id + return response, nil + } + } + if question.Qtype == dns.TypeA && options.Strategy == C.DomainStrategyIPv6Only || question.Qtype == dns.TypeAAAA && options.Strategy == C.DomainStrategyIPv4Only { + responseMessage := dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: message.Id, + Response: true, + Rcode: dns.RcodeSuccess, + }, + Question: []dns.Question{question}, + } + if c.logger != nil { + c.logger.DebugContext(ctx, "strategy rejected") + } + return &responseMessage, nil + } + messageId := message.Id + contextTransport, clientSubnetLoaded := transportTagFromContext(ctx) + if clientSubnetLoaded && transport.Tag() == contextTransport { + return nil, E.New("DNS query loopback in transport[", contextTransport, "]") + } + ctx = contextWithTransportTag(ctx, transport.Tag()) + if responseChecker != nil && c.rdrc != nil { + rejected := c.rdrc.LoadRDRC(transport.Tag(), question.Name, question.Qtype) + if rejected { + return nil, ErrResponseRejectedCached + } + } + ctx, cancel := context.WithTimeout(ctx, c.timeout) + response, err := transport.Exchange(ctx, message) + cancel() + if err != nil { + return nil, err + } + /*if question.Qtype == dns.TypeA || question.Qtype == dns.TypeAAAA { + validResponse := response + loop: + for { + var ( + addresses int + queryCNAME string + ) + for _, rawRR := range validResponse.Answer { + switch rr := rawRR.(type) { + case *dns.A: + break loop + case *dns.AAAA: + break loop + case *dns.CNAME: + queryCNAME = rr.Target + } + } + if queryCNAME == "" { + break + } + exMessage := *message + exMessage.Question = []dns.Question{{ + Name: queryCNAME, + Qtype: question.Qtype, + }} + validResponse, err = c.Exchange(ctx, transport, &exMessage, options, responseChecker) + if err != nil { + return nil, err + } + } + if validResponse != response { + response.Answer = append(response.Answer, validResponse.Answer...) + } + }*/ + if responseChecker != nil { + addr, addrErr := MessageToAddresses(response) + if addrErr != nil || !responseChecker(addr) { + if c.rdrc != nil { + c.rdrc.SaveRDRCAsync(transport.Tag(), question.Name, question.Qtype, c.logger) + } + logRejectedResponse(c.logger, ctx, response) + return response, ErrResponseRejected + } + } + if question.Qtype == dns.TypeHTTPS { + if options.Strategy == C.DomainStrategyIPv4Only || options.Strategy == C.DomainStrategyIPv6Only { + for _, rr := range response.Answer { + https, isHTTPS := rr.(*dns.HTTPS) + if !isHTTPS { + continue + } + content := https.SVCB + content.Value = common.Filter(content.Value, func(it dns.SVCBKeyValue) bool { + if options.Strategy == C.DomainStrategyIPv4Only { + return it.Key() != dns.SVCB_IPV6HINT + } else { + return it.Key() != dns.SVCB_IPV4HINT + } + }) + https.SVCB = content + } + } + } + var timeToLive uint32 + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive { + timeToLive = record.Header().Ttl + } + } + } + if options.RewriteTTL != nil { + timeToLive = *options.RewriteTTL + } + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + record.Header().Ttl = timeToLive + } + } + response.Id = messageId + if !disableCache { + c.storeCache(transport, question, response, timeToLive) + } + logExchangedResponse(c.logger, ctx, response, timeToLive) + return response, err +} + +func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, domain string, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error) { + domain = FqdnToDomain(domain) + dnsName := dns.Fqdn(domain) + if options.Strategy == C.DomainStrategyIPv4Only { + return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, options, responseChecker) + } else if options.Strategy == C.DomainStrategyIPv6Only { + return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, options, responseChecker) + } + var response4 []netip.Addr + var response6 []netip.Addr + var group task.Group + group.Append("exchange4", func(ctx context.Context) error { + response, err := c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, options, responseChecker) + if err != nil { + return err + } + response4 = response + return nil + }) + group.Append("exchange6", func(ctx context.Context) error { + response, err := c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, options, responseChecker) + if err != nil { + return err + } + response6 = response + return nil + }) + err := group.Run(ctx) + if len(response4) == 0 && len(response6) == 0 { + return nil, err + } + return sortAddresses(response4, response6, options.Strategy), nil +} + +func (c *Client) ClearCache() { + if c.cache != nil { + c.cache.Purge() + } + if c.transportCache != nil { + c.transportCache.Purge() + } +} + +func (c *Client) LookupCache(domain string, strategy C.DomainStrategy) ([]netip.Addr, bool) { + if c.disableCache || c.independentCache { + return nil, false + } + if dns.IsFqdn(domain) { + domain = domain[:len(domain)-1] + } + dnsName := dns.Fqdn(domain) + if strategy == C.DomainStrategyIPv4Only { + response, err := c.questionCache(dns.Question{ + Name: dnsName, + Qtype: dns.TypeA, + Qclass: dns.ClassINET, + }, nil) + if err != ErrNotCached { + return response, true + } + } else if strategy == C.DomainStrategyIPv6Only { + response, err := c.questionCache(dns.Question{ + Name: dnsName, + Qtype: dns.TypeAAAA, + Qclass: dns.ClassINET, + }, nil) + if err != ErrNotCached { + return response, true + } + } else { + response4, _ := c.questionCache(dns.Question{ + Name: dnsName, + Qtype: dns.TypeA, + Qclass: dns.ClassINET, + }, nil) + response6, _ := c.questionCache(dns.Question{ + Name: dnsName, + Qtype: dns.TypeAAAA, + Qclass: dns.ClassINET, + }, nil) + if len(response4) > 0 || len(response6) > 0 { + return sortAddresses(response4, response6, strategy), true + } + } + return nil, false +} + +func (c *Client) ExchangeCache(ctx context.Context, message *dns.Msg) (*dns.Msg, bool) { + if c.disableCache || c.independentCache || len(message.Question) != 1 { + return nil, false + } + question := message.Question[0] + response, ttl := c.loadResponse(question, nil) + if response == nil { + return nil, false + } + logCachedResponse(c.logger, ctx, response, ttl) + response.Id = message.Id + return response, true +} + +func sortAddresses(response4 []netip.Addr, response6 []netip.Addr, strategy C.DomainStrategy) []netip.Addr { + if strategy == C.DomainStrategyPreferIPv6 { + return append(response6, response4...) + } else { + return append(response4, response6...) + } +} + +func (c *Client) storeCache(transport adapter.DNSTransport, question dns.Question, message *dns.Msg, timeToLive uint32) { + if timeToLive == 0 { + return + } + if c.disableExpire { + if !c.independentCache { + c.cache.Add(question, message) + } else { + c.transportCache.Add(transportCacheKey{ + Question: question, + transportTag: transport.Tag(), + }, message) + } + return + } + if !c.independentCache { + c.cache.AddWithLifetime(question, message, time.Second*time.Duration(timeToLive)) + } else { + c.transportCache.AddWithLifetime(transportCacheKey{ + Question: question, + transportTag: transport.Tag(), + }, message, time.Second*time.Duration(timeToLive)) + } +} + +func (c *Client) lookupToExchange(ctx context.Context, transport adapter.DNSTransport, name string, qType uint16, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error) { + question := dns.Question{ + Name: name, + Qtype: qType, + Qclass: dns.ClassINET, + } + disableCache := c.disableCache || options.DisableCache + if !disableCache { + cachedAddresses, err := c.questionCache(question, transport) + if err != ErrNotCached { + return cachedAddresses, err + } + } + message := dns.Msg{ + MsgHdr: dns.MsgHdr{ + RecursionDesired: true, + }, + Question: []dns.Question{question}, + } + response, err := c.Exchange(ctx, transport, &message, options, responseChecker) + if err != nil { + return nil, err + } + return MessageToAddresses(response) +} + +func (c *Client) questionCache(question dns.Question, transport adapter.DNSTransport) ([]netip.Addr, error) { + response, _ := c.loadResponse(question, transport) + if response == nil { + return nil, ErrNotCached + } + return MessageToAddresses(response) +} + +func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int) { + var ( + response *dns.Msg + loaded bool + ) + if c.disableExpire { + if !c.independentCache { + response, loaded = c.cache.Get(question) + } else { + response, loaded = c.transportCache.Get(transportCacheKey{ + Question: question, + transportTag: transport.Tag(), + }) + } + if !loaded { + return nil, 0 + } + return response.Copy(), 0 + } else { + var expireAt time.Time + if !c.independentCache { + response, expireAt, loaded = c.cache.GetWithLifetime(question) + } else { + response, expireAt, loaded = c.transportCache.GetWithLifetime(transportCacheKey{ + Question: question, + transportTag: transport.Tag(), + }) + } + if !loaded { + return nil, 0 + } + timeNow := time.Now() + if timeNow.After(expireAt) { + if !c.independentCache { + c.cache.Remove(question) + } else { + c.transportCache.Remove(transportCacheKey{ + Question: question, + transportTag: transport.Tag(), + }) + } + return nil, 0 + } + var originTTL int + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + if originTTL == 0 || record.Header().Ttl > 0 && int(record.Header().Ttl) < originTTL { + originTTL = int(record.Header().Ttl) + } + } + } + nowTTL := int(expireAt.Sub(timeNow).Seconds()) + if nowTTL < 0 { + nowTTL = 0 + } + response = response.Copy() + if originTTL > 0 { + duration := uint32(originTTL - nowTTL) + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + record.Header().Ttl = record.Header().Ttl - duration + } + } + } else { + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + record.Header().Ttl = uint32(nowTTL) + } + } + } + return response, nowTTL + } +} + +func MessageToAddresses(response *dns.Msg) ([]netip.Addr, error) { + if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError { + return nil, RCodeError(response.Rcode) + } + addresses := make([]netip.Addr, 0, len(response.Answer)) + for _, rawAnswer := range response.Answer { + switch answer := rawAnswer.(type) { + case *dns.A: + addresses = append(addresses, M.AddrFromIP(answer.A)) + case *dns.AAAA: + addresses = append(addresses, M.AddrFromIP(answer.AAAA)) + case *dns.HTTPS: + for _, value := range answer.SVCB.Value { + if value.Key() == dns.SVCB_IPV4HINT || value.Key() == dns.SVCB_IPV6HINT { + addresses = append(addresses, common.Map(strings.Split(value.String(), ","), M.ParseAddr)...) + } + } + } + } + return addresses, nil +} + +func wrapError(err error) error { + switch dnsErr := err.(type) { + case *net.DNSError: + if dnsErr.IsNotFound { + return RCodeNameError + } + case *net.AddrError: + return RCodeNameError + } + return err +} + +type transportKey struct{} + +func contextWithTransportTag(ctx context.Context, transportTag string) context.Context { + return context.WithValue(ctx, transportKey{}, transportTag) +} + +func transportTagFromContext(ctx context.Context) (string, bool) { + value, loaded := ctx.Value(transportKey{}).(string) + return value, loaded +} + +func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, timeToLive uint32) *dns.Msg { + response := dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: id, + Rcode: dns.RcodeSuccess, + Response: true, + }, + Question: []dns.Question{question}, + } + for _, address := range addresses { + if address.Is4() { + response.Answer = append(response.Answer, &dns.A{ + Hdr: dns.RR_Header{ + Name: question.Name, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: timeToLive, + }, + A: address.AsSlice(), + }) + } else { + response.Answer = append(response.Answer, &dns.AAAA{ + Hdr: dns.RR_Header{ + Name: question.Name, + Rrtype: dns.TypeAAAA, + Class: dns.ClassINET, + Ttl: timeToLive, + }, + AAAA: address.AsSlice(), + }) + } + } + return &response +} diff --git a/dns/client_log.go b/dns/client_log.go new file mode 100644 index 00000000..67d00708 --- /dev/null +++ b/dns/client_log.go @@ -0,0 +1,69 @@ +package dns + +import ( + "context" + "strings" + + "github.com/sagernet/sing/common/logger" + + "github.com/miekg/dns" +) + +func logCachedResponse(logger logger.ContextLogger, ctx context.Context, response *dns.Msg, ttl int) { + if logger == nil || len(response.Question) == 0 { + return + } + domain := FqdnToDomain(response.Question[0].Name) + logger.DebugContext(ctx, "cached ", domain, " ", dns.RcodeToString[response.Rcode], " ", ttl) + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + logger.InfoContext(ctx, "cached ", dns.Type(record.Header().Rrtype).String(), " ", FormatQuestion(record.String())) + } + } +} + +func logExchangedResponse(logger logger.ContextLogger, ctx context.Context, response *dns.Msg, ttl uint32) { + if logger == nil || len(response.Question) == 0 { + return + } + domain := FqdnToDomain(response.Question[0].Name) + logger.DebugContext(ctx, "exchanged ", domain, " ", dns.RcodeToString[response.Rcode], " ", ttl) + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + logger.InfoContext(ctx, "exchanged ", dns.Type(record.Header().Rrtype).String(), " ", FormatQuestion(record.String())) + } + } +} + +func logRejectedResponse(logger logger.ContextLogger, ctx context.Context, response *dns.Msg) { + if logger == nil || len(response.Question) == 0 { + return + } + for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} { + for _, record := range recordList { + logger.InfoContext(ctx, "rejected ", dns.Type(record.Header().Rrtype).String(), " ", FormatQuestion(record.String())) + } + } +} + +func FqdnToDomain(fqdn string) string { + if dns.IsFqdn(fqdn) { + return fqdn[:len(fqdn)-1] + } + return fqdn +} + +func FormatQuestion(string string) string { + for strings.HasPrefix(string, ";") { + string = string[1:] + } + string = strings.ReplaceAll(string, "\t", " ") + string = strings.ReplaceAll(string, "\n", " ") + string = strings.ReplaceAll(string, ";; ", " ") + string = strings.ReplaceAll(string, "; ", " ") + + for strings.Contains(string, " ") { + string = strings.ReplaceAll(string, " ", " ") + } + return strings.TrimSpace(string) +} diff --git a/dns/client_truncate.go b/dns/client_truncate.go new file mode 100644 index 00000000..e64064e6 --- /dev/null +++ b/dns/client_truncate.go @@ -0,0 +1,29 @@ +package dns + +import ( + "github.com/sagernet/sing/common/buf" + + "github.com/miekg/dns" +) + +func TruncateDNSMessage(request *dns.Msg, response *dns.Msg, headroom int) (*buf.Buffer, error) { + maxLen := 512 + if edns0Option := request.IsEdns0(); edns0Option != nil { + if udpSize := int(edns0Option.UDPSize()); udpSize > 512 { + maxLen = udpSize + } + } + responseLen := response.Len() + if responseLen > maxLen { + response.Truncate(maxLen) + } + buffer := buf.NewSize(headroom*2 + 1 + responseLen) + buffer.Resize(headroom, 0) + rawMessage, err := response.PackBuffer(buffer.FreeBytes()) + if err != nil { + buffer.Release() + return nil, err + } + buffer.Truncate(len(rawMessage)) + return buffer, nil +} diff --git a/dns/extension_edns0_subnet.go b/dns/extension_edns0_subnet.go new file mode 100644 index 00000000..1c4033d3 --- /dev/null +++ b/dns/extension_edns0_subnet.go @@ -0,0 +1,56 @@ +package dns + +import ( + "net/netip" + + "github.com/miekg/dns" +) + +func SetClientSubnet(message *dns.Msg, clientSubnet netip.Prefix, override bool) *dns.Msg { + var ( + optRecord *dns.OPT + subnetOption *dns.EDNS0_SUBNET + ) +findExists: + for _, record := range message.Extra { + var isOPTRecord bool + if optRecord, isOPTRecord = record.(*dns.OPT); isOPTRecord { + for _, option := range optRecord.Option { + var isEDNS0Subnet bool + subnetOption, isEDNS0Subnet = option.(*dns.EDNS0_SUBNET) + if isEDNS0Subnet { + if !override { + return message + } + break findExists + } + } + } + } + if optRecord == nil { + exMessage := *message + message = &exMessage + optRecord = &dns.OPT{ + Hdr: dns.RR_Header{ + Name: ".", + Rrtype: dns.TypeOPT, + }, + } + message.Extra = append(message.Extra, optRecord) + } else { + message = message.Copy() + } + if subnetOption == nil { + subnetOption = new(dns.EDNS0_SUBNET) + optRecord.Option = append(optRecord.Option, subnetOption) + } + subnetOption.Code = dns.EDNS0SUBNET + if clientSubnet.Addr().Is4() { + subnetOption.Family = 1 + } else { + subnetOption.Family = 2 + } + subnetOption.SourceNetmask = uint8(clientSubnet.Bits()) + subnetOption.Address = clientSubnet.Addr().AsSlice() + return message +} diff --git a/dns/rcode.go b/dns/rcode.go new file mode 100644 index 00000000..5b7e52cc --- /dev/null +++ b/dns/rcode.go @@ -0,0 +1,33 @@ +package dns + +import F "github.com/sagernet/sing/common/format" + +const ( + RCodeSuccess RCodeError = 0 // NoError + RCodeFormatError RCodeError = 1 // FormErr + RCodeServerFailure RCodeError = 2 // ServFail + RCodeNameError RCodeError = 3 // NXDomain + RCodeNotImplemented RCodeError = 4 // NotImp + RCodeRefused RCodeError = 5 // Refused +) + +type RCodeError uint16 + +func (e RCodeError) Error() string { + switch e { + case RCodeSuccess: + return "success" + case RCodeFormatError: + return "format error" + case RCodeServerFailure: + return "server failure" + case RCodeNameError: + return "name error" + case RCodeNotImplemented: + return "not implemented" + case RCodeRefused: + return "refused" + default: + return F.ToString("unknown error: ", uint16(e)) + } +} diff --git a/dns/router.go b/dns/router.go new file mode 100644 index 00000000..8ecb8891 --- /dev/null +++ b/dns/router.go @@ -0,0 +1,437 @@ +package dns + +import ( + "context" + "errors" + "net/netip" + "strings" + "time" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/taskmonitor" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/libbox/platform" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + R "github.com/sagernet/sing-box/route/rule" + "github.com/sagernet/sing-tun" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + F "github.com/sagernet/sing/common/format" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/contrab/freelru" + "github.com/sagernet/sing/contrab/maphash" + "github.com/sagernet/sing/service" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSRouter = (*Router)(nil) + +type Router struct { + ctx context.Context + logger logger.ContextLogger + transport adapter.DNSTransportManager + outbound adapter.OutboundManager + client adapter.DNSClient + rules []adapter.DNSRule + defaultDomainStrategy C.DomainStrategy + dnsReverseMapping freelru.Cache[netip.Addr, string] + platformInterface platform.Interface +} + +func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOptions) *Router { + router := &Router{ + ctx: ctx, + logger: logFactory.NewLogger("dns"), + transport: service.FromContext[adapter.DNSTransportManager](ctx), + outbound: service.FromContext[adapter.OutboundManager](ctx), + rules: make([]adapter.DNSRule, 0, len(options.Rules)), + defaultDomainStrategy: C.DomainStrategy(options.Strategy), + } + router.client = NewClient(ClientOptions{ + DisableCache: options.DNSClientOptions.DisableCache, + DisableExpire: options.DNSClientOptions.DisableExpire, + IndependentCache: options.DNSClientOptions.IndependentCache, + CacheCapacity: options.DNSClientOptions.CacheCapacity, + RDRC: func() adapter.RDRCStore { + cacheFile := service.FromContext[adapter.CacheFile](ctx) + if cacheFile == nil { + return nil + } + if !cacheFile.StoreRDRC() { + return nil + } + return cacheFile + }, + Logger: router.logger, + }) + if options.ReverseMapping { + router.dnsReverseMapping = common.Must1(freelru.NewSharded[netip.Addr, string](1024, maphash.NewHasher[netip.Addr]().Hash32)) + } + return router +} + +func (r *Router) Initialize(rules []option.DNSRule) error { + for i, ruleOptions := range rules { + dnsRule, err := R.NewDNSRule(r.ctx, r.logger, ruleOptions, true) + if err != nil { + return E.Cause(err, "parse dns rule[", i, "]") + } + r.rules = append(r.rules, dnsRule) + } + return nil +} + +func (r *Router) Start(stage adapter.StartStage) error { + monitor := taskmonitor.New(r.logger, C.StartTimeout) + switch stage { + case adapter.StartStateStart: + monitor.Start("initialize DNS client") + r.client.Start() + monitor.Finish() + + for i, rule := range r.rules { + monitor.Start("initialize DNS rule[", i, "]") + err := rule.Start() + monitor.Finish() + if err != nil { + return E.Cause(err, "initialize DNS rule[", i, "]") + } + } + } + return nil +} + +func (r *Router) Close() error { + monitor := taskmonitor.New(r.logger, C.StopTimeout) + var err error + for i, rule := range r.rules { + monitor.Start("close dns rule[", i, "]") + err = E.Append(err, rule.Close(), func(err error) error { + return E.Cause(err, "close dns rule[", i, "]") + }) + monitor.Finish() + } + return err +} + +func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int, isAddressQuery bool, options *adapter.DNSQueryOptions) (adapter.DNSTransport, adapter.DNSRule, int) { + metadata := adapter.ContextFrom(ctx) + if metadata == nil { + panic("no context") + } + var currentRuleIndex int + if ruleIndex != -1 { + currentRuleIndex = ruleIndex + 1 + } + for ; currentRuleIndex < len(r.rules); currentRuleIndex++ { + currentRule := r.rules[currentRuleIndex] + if currentRule.WithAddressLimit() && !isAddressQuery { + continue + } + metadata.ResetRuleCache() + if currentRule.Match(metadata) { + displayRuleIndex := currentRuleIndex + if displayRuleIndex != -1 { + displayRuleIndex += displayRuleIndex + 1 + } + ruleDescription := currentRule.String() + if ruleDescription != "" { + r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] ", currentRule, " => ", currentRule.Action()) + } else { + r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) + } + switch action := currentRule.Action().(type) { + case *R.RuleActionDNSRoute: + transport, loaded := r.transport.Transport(action.Server) + if !loaded { + r.logger.ErrorContext(ctx, "transport not found: ", action.Server) + continue + } + isFakeIP := transport.Type() == C.DNSTypeFakeIP + if isFakeIP && !allowFakeIP { + continue + } + if action.Strategy != C.DomainStrategyAsIS { + options.Strategy = action.Strategy + } + if isFakeIP || action.DisableCache { + options.DisableCache = true + } + if action.RewriteTTL != nil { + options.RewriteTTL = action.RewriteTTL + } + if action.ClientSubnet.IsValid() { + options.ClientSubnet = action.ClientSubnet + } + if legacyTransport, isLegacy := transport.(adapter.LegacyDNSTransport); isLegacy { + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = legacyTransport.LegacyStrategy() + } + if !options.ClientSubnet.IsValid() { + options.ClientSubnet = legacyTransport.LegacyClientSubnet() + } + } + r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) + return transport, currentRule, currentRuleIndex + case *R.RuleActionDNSRouteOptions: + if action.Strategy != C.DomainStrategyAsIS { + options.Strategy = action.Strategy + } + if action.DisableCache { + options.DisableCache = true + } + if action.RewriteTTL != nil { + options.RewriteTTL = action.RewriteTTL + } + if action.ClientSubnet.IsValid() { + options.ClientSubnet = action.ClientSubnet + } + r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) + case *R.RuleActionReject: + r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) + return nil, currentRule, currentRuleIndex + } + } + } + return r.transport.Default(), nil, -1 +} + +func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapter.DNSQueryOptions) (*mDNS.Msg, error) { + if len(message.Question) != 1 { + r.logger.WarnContext(ctx, "bad question size: ", len(message.Question)) + responseMessage := mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Response: true, + Rcode: mDNS.RcodeFormatError, + }, + Question: message.Question, + } + return &responseMessage, nil + } + r.logger.DebugContext(ctx, "exchange ", FormatQuestion(message.Question[0].String())) + var ( + transport adapter.DNSTransport + err error + ) + response, cached := r.client.ExchangeCache(ctx, message) + if !cached { + var metadata *adapter.InboundContext + ctx, metadata = adapter.ExtendContext(ctx) + metadata.Destination = M.Socksaddr{} + metadata.QueryType = message.Question[0].Qtype + switch metadata.QueryType { + case mDNS.TypeA: + metadata.IPVersion = 4 + case mDNS.TypeAAAA: + metadata.IPVersion = 6 + } + metadata.Domain = FqdnToDomain(message.Question[0].Name) + if options.Transport != nil { + transport = options.Transport + if legacyTransport, isLegacy := transport.(adapter.LegacyDNSTransport); isLegacy { + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = legacyTransport.LegacyStrategy() + } + if !options.ClientSubnet.IsValid() { + options.ClientSubnet = legacyTransport.LegacyClientSubnet() + } + } + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = r.defaultDomainStrategy + } + response, err = r.client.Exchange(ctx, transport, message, options, nil) + } else { + var ( + rule adapter.DNSRule + ruleIndex int + ) + ruleIndex = -1 + for { + dnsCtx := adapter.OverrideContext(ctx) + dnsOptions := options + transport, rule, ruleIndex = r.matchDNS(ctx, true, ruleIndex, isAddressQuery(message), &dnsOptions) + if rule != nil { + switch action := rule.Action().(type) { + case *R.RuleActionReject: + switch action.Method { + case C.RuleActionRejectMethodDefault: + return FixedResponse(message.Id, message.Question[0], nil, 0), nil + case C.RuleActionRejectMethodDrop: + return nil, tun.ErrDrop + } + } + } + var responseCheck func(responseAddrs []netip.Addr) bool + if rule != nil && rule.WithAddressLimit() { + responseCheck = func(responseAddrs []netip.Addr) bool { + metadata.DestinationAddresses = responseAddrs + return rule.MatchAddressLimit(metadata) + } + } + if dnsOptions.Strategy == C.DomainStrategyAsIS { + dnsOptions.Strategy = r.defaultDomainStrategy + } + response, err = r.client.Exchange(dnsCtx, transport, message, dnsOptions, responseCheck) + var rejected bool + if err != nil { + if errors.Is(err, ErrResponseRejectedCached) { + rejected = true + r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())), " (cached)") + } else if errors.Is(err, ErrResponseRejected) { + rejected = true + r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String()))) + } else if len(message.Question) > 0 { + r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String()))) + } else { + r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ")) + } + } + if responseCheck != nil && rejected { + continue + } + break + } + } + } + if err != nil { + return nil, err + } + if r.dnsReverseMapping != nil && len(message.Question) > 0 && response != nil && len(response.Answer) > 0 { + if transport == nil || transport.Type() != C.DNSTypeFakeIP { + for _, answer := range response.Answer { + switch record := answer.(type) { + case *mDNS.A: + r.dnsReverseMapping.AddWithLifetime(M.AddrFromIP(record.A), FqdnToDomain(record.Hdr.Name), time.Duration(record.Hdr.Ttl)*time.Second) + case *mDNS.AAAA: + r.dnsReverseMapping.AddWithLifetime(M.AddrFromIP(record.AAAA), FqdnToDomain(record.Hdr.Name), time.Duration(record.Hdr.Ttl)*time.Second) + } + } + } + } + return response, nil +} + +func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, error) { + var ( + responseAddrs []netip.Addr + cached bool + err error + ) + printResult := func() { + if err != nil { + if errors.Is(err, ErrResponseRejectedCached) { + r.logger.DebugContext(ctx, "response rejected for ", domain, " (cached)") + } else if errors.Is(err, ErrResponseRejected) { + r.logger.DebugContext(ctx, "response rejected for ", domain) + } else { + r.logger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain)) + } + } else if len(responseAddrs) == 0 { + r.logger.ErrorContext(ctx, "lookup failed for ", domain, ": empty result") + err = RCodeNameError + } + } + responseAddrs, cached = r.client.LookupCache(domain, options.Strategy) + if cached { + if len(responseAddrs) == 0 { + return nil, RCodeNameError + } + return responseAddrs, nil + } + r.logger.DebugContext(ctx, "lookup domain ", domain) + ctx, metadata := adapter.ExtendContext(ctx) + metadata.Destination = M.Socksaddr{} + metadata.Domain = FqdnToDomain(domain) + if options.Transport != nil { + transport := options.Transport + if legacyTransport, isLegacy := transport.(adapter.LegacyDNSTransport); isLegacy { + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = r.defaultDomainStrategy + } + if !options.ClientSubnet.IsValid() { + options.ClientSubnet = legacyTransport.LegacyClientSubnet() + } + } + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = r.defaultDomainStrategy + } + responseAddrs, err = r.client.Lookup(ctx, transport, domain, options, nil) + } else { + var ( + transport adapter.DNSTransport + rule adapter.DNSRule + ruleIndex int + ) + ruleIndex = -1 + for { + dnsCtx := adapter.OverrideContext(ctx) + transport, rule, ruleIndex = r.matchDNS(ctx, false, ruleIndex, true, &options) + if rule != nil { + switch action := rule.Action().(type) { + case *R.RuleActionReject: + switch action.Method { + case C.RuleActionRejectMethodDefault: + return nil, nil + case C.RuleActionRejectMethodDrop: + return nil, tun.ErrDrop + } + } + } + var responseCheck func(responseAddrs []netip.Addr) bool + if rule != nil && rule.WithAddressLimit() { + responseCheck = func(responseAddrs []netip.Addr) bool { + metadata.DestinationAddresses = responseAddrs + return rule.MatchAddressLimit(metadata) + } + } + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = r.defaultDomainStrategy + } + responseAddrs, err = r.client.Lookup(dnsCtx, transport, domain, options, responseCheck) + if responseCheck == nil || err == nil { + break + } + printResult() + } + } + printResult() + if len(responseAddrs) > 0 { + r.logger.InfoContext(ctx, "lookup succeed for ", domain, ": ", strings.Join(F.MapToString(responseAddrs), " ")) + } + return responseAddrs, err +} + +func isAddressQuery(message *mDNS.Msg) bool { + for _, question := range message.Question { + if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA || question.Qtype == mDNS.TypeHTTPS { + return true + } + } + return false +} + +func (r *Router) ClearCache() { + r.client.ClearCache() + if r.platformInterface != nil { + r.platformInterface.ClearDNSCache() + } +} + +func (r *Router) LookupReverseMapping(ip netip.Addr) (string, bool) { + if r.dnsReverseMapping == nil { + return "", false + } + domain, loaded := r.dnsReverseMapping.Get(ip) + return domain, loaded +} + +func (r *Router) ResetNetwork() { + r.ClearCache() + for _, transport := range r.transport.Transports() { + transport.Reset() + } +} diff --git a/transport/dhcp/server.go b/dns/transport/dhcp/dhcp.go similarity index 66% rename from transport/dhcp/server.go rename to dns/transport/dhcp/dhcp.go index 8b9187f0..c75d7369 100644 --- a/transport/dhcp/server.go +++ b/dns/transport/dhcp/dhcp.go @@ -3,9 +3,6 @@ package dhcp import ( "context" "net" - "net/netip" - "net/url" - "os" "runtime" "strings" "sync" @@ -14,13 +11,18 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport" + "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/task" "github.com/sagernet/sing/common/x/list" "github.com/sagernet/sing/service" @@ -29,76 +31,70 @@ import ( mDNS "github.com/miekg/dns" ) -func init() { - dns.RegisterTransport([]string{"dhcp"}, func(options dns.TransportOptions) (dns.Transport, error) { - return NewTransport(options) - }) +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.DHCPDNSServerOptions](registry, C.DNSTypeDHCP, NewTransport) } +var _ adapter.DNSTransport = (*Transport)(nil) + type Transport struct { - options dns.TransportOptions - router adapter.Router + dns.TransportAdapter + ctx context.Context + dialer N.Dialer + logger logger.ContextLogger networkManager adapter.NetworkManager interfaceName string - autoInterface bool interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback] - transports []dns.Transport + transports []adapter.DNSTransport updateAccess sync.Mutex updatedAt time.Time } -func NewTransport(options dns.TransportOptions) (*Transport, error) { - linkURL, err := url.Parse(options.Address) +func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.DHCPDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewLocalDialer(ctx, options.LocalDNSServerOptions) if err != nil { return nil, err } - if linkURL.Host == "" { - return nil, E.New("missing interface name for DHCP") - } - transport := &Transport{ - options: options, - networkManager: service.FromContext[adapter.NetworkManager](options.Context), - interfaceName: linkURL.Host, - autoInterface: linkURL.Host == "auto", - } - return transport, nil + return &Transport{ + TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeDHCP, tag, options.LocalDNSServerOptions), + ctx: ctx, + dialer: transportDialer, + logger: logger, + networkManager: service.FromContext[adapter.NetworkManager](ctx), + interfaceName: options.Interface, + }, nil } -func (t *Transport) Name() string { - return t.options.Name -} - -func (t *Transport) Start() error { +func (t *Transport) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } err := t.fetchServers() if err != nil { return err } - if t.autoInterface { + if t.interfaceName == "" { t.interfaceCallback = t.networkManager.InterfaceMonitor().RegisterCallback(t.interfaceUpdated) } return nil } +func (t *Transport) Close() error { + for _, transport := range t.transports { + transport.Reset() + } + if t.interfaceCallback != nil { + t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback) + } + return nil +} + func (t *Transport) Reset() { for _, transport := range t.transports { transport.Reset() } } -func (t *Transport) Close() error { - for _, transport := range t.transports { - transport.Close() - } - if t.interfaceCallback != nil { - t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback) - } - return nil -} - -func (t *Transport) Raw() bool { - return true -} - func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { err := t.fetchServers() if err != nil { @@ -120,7 +116,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, } func (t *Transport) fetchInterface() (*control.Interface, error) { - if t.autoInterface { + if t.interfaceName == "" { if t.networkManager.InterfaceMonitor() == nil { return nil, E.New("missing monitor for auto DHCP, set route.auto_detect_interface") } @@ -152,8 +148,8 @@ func (t *Transport) updateServers() error { return E.Cause(err, "dhcp: prepare interface") } - t.options.Logger.Info("dhcp: query DNS servers on ", iface.Name) - fetchCtx, cancel := context.WithTimeout(t.options.Context, C.DHCPTimeout) + t.logger.Info("dhcp: query DNS servers on ", iface.Name) + fetchCtx, cancel := context.WithTimeout(t.ctx, C.DHCPTimeout) err = t.fetchServers0(fetchCtx, iface) cancel() if err != nil { @@ -169,7 +165,7 @@ func (t *Transport) updateServers() error { func (t *Transport) interfaceUpdated(defaultInterface *control.Interface, flags int) { err := t.updateServers() if err != nil { - t.options.Logger.Error("update servers: ", err) + t.logger.Error("update servers: ", err) } } @@ -181,7 +177,7 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface) if runtime.GOOS == "linux" || runtime.GOOS == "android" { listenAddr = "255.255.255.255:68" } - packetConn, err := listener.ListenPacket(t.options.Context, "udp4", listenAddr) + packetConn, err := listener.ListenPacket(t.ctx, "udp4", listenAddr) if err != nil { return err } @@ -219,17 +215,17 @@ func (t *Transport) fetchServersResponse(iface *control.Interface, packetConn ne dhcpPacket, err := dhcpv4.FromBytes(buffer.Bytes()) if err != nil { - t.options.Logger.Trace("dhcp: parse DHCP response: ", err) + t.logger.Trace("dhcp: parse DHCP response: ", err) return err } if dhcpPacket.MessageType() != dhcpv4.MessageTypeOffer { - t.options.Logger.Trace("dhcp: expected OFFER response, but got ", dhcpPacket.MessageType()) + t.logger.Trace("dhcp: expected OFFER response, but got ", dhcpPacket.MessageType()) continue } if dhcpPacket.TransactionID != transactionID { - t.options.Logger.Trace("dhcp: expected transaction ID ", transactionID, ", but got ", dhcpPacket.TransactionID) + t.logger.Trace("dhcp: expected transaction ID ", transactionID, ", but got ", dhcpPacket.TransactionID) continue } @@ -237,44 +233,27 @@ func (t *Transport) fetchServersResponse(iface *control.Interface, packetConn ne if len(dns) == 0 { return nil } - - var addrs []netip.Addr - for _, ip := range dns { - addr, _ := netip.AddrFromSlice(ip) - addrs = append(addrs, addr.Unmap()) - } - return t.recreateServers(iface, addrs) + return t.recreateServers(iface, common.Map(dns, func(it net.IP) M.Socksaddr { + return M.SocksaddrFrom(M.AddrFromIP(it), 53) + })) } } -func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []netip.Addr) error { +func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []M.Socksaddr) error { if len(serverAddrs) > 0 { - t.options.Logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, func(it netip.Addr) string { - return it.String() - }), ","), "]") + t.logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, M.Socksaddr.String), ","), "]") } - serverDialer := common.Must1(dialer.NewDefault(t.options.Context, option.DialerOptions{ + serverDialer := common.Must1(dialer.NewDefault(t.ctx, option.DialerOptions{ BindInterface: iface.Name, UDPFragmentDefault: true, })) - var transports []dns.Transport + var transports []adapter.DNSTransport for _, serverAddr := range serverAddrs { - newOptions := t.options - newOptions.Address = serverAddr.String() - newOptions.Dialer = serverDialer - serverTransport, err := dns.NewUDPTransport(newOptions) - if err != nil { - return E.Cause(err, "create UDP transport from DHCP result: ", serverAddr) - } - transports = append(transports, serverTransport) + transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, serverAddr)) } for _, transport := range t.transports { - transport.Close() + transport.Reset() } t.transports = transports return nil } - -func (t *Transport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) { - return nil, os.ErrInvalid -} diff --git a/dns/transport/fakeip/fakeip.go b/dns/transport/fakeip/fakeip.go new file mode 100644 index 00000000..07f0fd09 --- /dev/null +++ b/dns/transport/fakeip/fakeip.go @@ -0,0 +1,67 @@ +package fakeip + +import ( + "context" + "net/netip" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + + mDNS "github.com/miekg/dns" +) + +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.FakeIPDNSServerOptions](registry, C.DNSTypeFakeIP, NewTransport) +} + +var _ adapter.FakeIPTransport = (*Transport)(nil) + +type Transport struct { + dns.TransportAdapter + logger logger.ContextLogger + store adapter.FakeIPStore +} + +func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.FakeIPDNSServerOptions) (adapter.DNSTransport, error) { + store := NewStore(ctx, logger, options.Inet4Range.Build(netip.Prefix{}), options.Inet6Range.Build(netip.Prefix{})) + return &Transport{ + TransportAdapter: dns.NewTransportAdapter(C.DNSTypeFakeIP, tag, nil), + logger: logger, + store: store, + }, nil +} + +func (t *Transport) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + return t.store.Start() +} + +func (t *Transport) Close() error { + return t.store.Close() +} + +func (t *Transport) Reset() { +} + +func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + question := message.Question[0] + if question.Qtype != mDNS.TypeA && question.Qtype != mDNS.TypeAAAA { + return nil, E.New("only IP queries are supported by fakeip") + } + address, err := t.store.Create(dns.FqdnToDomain(question.Name), question.Qtype == mDNS.TypeAAAA) + if err != nil { + return nil, err + } + return dns.FixedResponse(message.Id, question, []netip.Addr{address}, C.DefaultDNSTTL), nil +} + +func (t *Transport) Store() adapter.FakeIPStore { + return t.store +} diff --git a/transport/fakeip/memory.go b/dns/transport/fakeip/memory.go similarity index 100% rename from transport/fakeip/memory.go rename to dns/transport/fakeip/memory.go diff --git a/transport/fakeip/store.go b/dns/transport/fakeip/store.go similarity index 100% rename from transport/fakeip/store.go rename to dns/transport/fakeip/store.go diff --git a/dns/transport/hosts/hosts.go b/dns/transport/hosts/hosts.go new file mode 100644 index 00000000..29f6778a --- /dev/null +++ b/dns/transport/hosts/hosts.go @@ -0,0 +1,63 @@ +package hosts + +import ( + "context" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + + mDNS "github.com/miekg/dns" +) + +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.HostsDNSServerOptions](registry, C.DNSTypeHosts, NewTransport) +} + +var _ adapter.DNSTransport = (*Transport)(nil) + +type Transport struct { + dns.TransportAdapter + files []*File +} + +func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.HostsDNSServerOptions) (adapter.DNSTransport, error) { + var files []*File + if len(options.Path) == 0 { + files = append(files, NewFile(DefaultPath)) + } else { + for _, path := range options.Path { + files = append(files, NewFile(path)) + } + } + return &Transport{ + TransportAdapter: dns.NewTransportAdapter(C.DNSTypeHosts, tag, nil), + files: files, + }, nil +} + +func (t *Transport) Reset() { +} + +func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + question := message.Question[0] + domain := dns.FqdnToDomain(question.Name) + if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA { + for _, file := range t.files { + addresses := file.Lookup(domain) + if len(addresses) > 0 { + return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil + } + } + } + return &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeNameError, + Response: true, + }, + Question: []mDNS.Question{question}, + }, nil +} diff --git a/dns/transport/hosts/hosts_file.go b/dns/transport/hosts/hosts_file.go new file mode 100644 index 00000000..7ff34f69 --- /dev/null +++ b/dns/transport/hosts/hosts_file.go @@ -0,0 +1,102 @@ +package hosts + +import ( + "bufio" + "errors" + "io" + "net/netip" + "os" + "strings" + "sync" + "time" + + "github.com/miekg/dns" +) + +const cacheMaxAge = 5 * time.Second + +type File struct { + path string + access sync.Mutex + byName map[string][]netip.Addr + expire time.Time + modTime time.Time + size int64 +} + +func NewFile(path string) *File { + return &File{ + path: path, + } +} + +func (f *File) Lookup(name string) []netip.Addr { + f.access.Lock() + defer f.access.Unlock() + f.update() + return f.byName[name] +} + +func (f *File) update() { + now := time.Now() + if now.Before(f.expire) && len(f.byName) > 0 { + return + } + stat, err := os.Stat(f.path) + if err != nil { + return + } + if f.modTime.Equal(stat.ModTime()) && f.size == stat.Size() { + f.expire = now.Add(cacheMaxAge) + return + } + byName := make(map[string][]netip.Addr) + file, err := os.Open(f.path) + if err != nil { + return + } + defer file.Close() + reader := bufio.NewReader(file) + var ( + prefix []byte + line []byte + isPrefix bool + ) + for { + line, isPrefix, err = reader.ReadLine() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return + } + if isPrefix { + prefix = append(prefix, line...) + continue + } else if len(prefix) > 0 { + line = append(prefix, line...) + prefix = nil + } + commentIndex := strings.IndexRune(string(line), '#') + if commentIndex != -1 { + line = line[:commentIndex] + } + fields := strings.Fields(string(line)) + if len(fields) < 2 { + continue + } + var addr netip.Addr + addr, err = netip.ParseAddr(fields[0]) + if err != nil { + continue + } + for index := 1; index < len(fields); index++ { + canonicalName := dns.CanonicalName(fields[index]) + byName[canonicalName] = append(byName[canonicalName], addr) + } + } + f.expire = now.Add(cacheMaxAge) + f.modTime = stat.ModTime() + f.size = stat.Size() + f.byName = byName +} diff --git a/dns/transport/hosts/hosts_test.go b/dns/transport/hosts/hosts_test.go new file mode 100644 index 00000000..944aa437 --- /dev/null +++ b/dns/transport/hosts/hosts_test.go @@ -0,0 +1,16 @@ +package hosts_test + +import ( + "net/netip" + "testing" + + "github.com/sagernet/sing-box/dns/transport/hosts" + + "github.com/stretchr/testify/require" +) + +func TestHosts(t *testing.T) { + t.Parallel() + require.Equal(t, []netip.Addr{netip.AddrFrom4([4]byte{127, 0, 0, 1}), netip.IPv6Loopback()}, hosts.NewFile("testdata/hosts").Lookup("localhost.")) + require.NotEmpty(t, hosts.NewFile(hosts.DefaultPath).Lookup("localhost.")) +} diff --git a/dns/transport/hosts/hosts_unix.go b/dns/transport/hosts/hosts_unix.go new file mode 100644 index 00000000..4caed8b4 --- /dev/null +++ b/dns/transport/hosts/hosts_unix.go @@ -0,0 +1,5 @@ +//go:build !windows + +package hosts + +var DefaultPath = "/etc/hosts" diff --git a/dns/transport/hosts/hosts_windows.go b/dns/transport/hosts/hosts_windows.go new file mode 100644 index 00000000..3144e50d --- /dev/null +++ b/dns/transport/hosts/hosts_windows.go @@ -0,0 +1,17 @@ +package hosts + +import ( + "path/filepath" + + "golang.org/x/sys/windows" +) + +var DefaultPath string + +func init() { + systemDirectory, err := windows.GetSystemDirectory() + if err != nil { + systemDirectory = "C:\\Windows\\System32" + } + DefaultPath = filepath.Join(systemDirectory, "Drivers/etc/hosts") +} diff --git a/dns/transport/hosts/testdata/hosts b/dns/transport/hosts/testdata/hosts new file mode 100644 index 00000000..9ddcc8c1 --- /dev/null +++ b/dns/transport/hosts/testdata/hosts @@ -0,0 +1,2 @@ +127.0.0.1 localhost +::1 localhost diff --git a/dns/transport/https.go b/dns/transport/https.go new file mode 100644 index 00000000..1cfb2574 --- /dev/null +++ b/dns/transport/https.go @@ -0,0 +1,204 @@ +package transport + +import ( + "bytes" + "context" + "io" + "net" + "net/http" + "net/url" + "strconv" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + aTLS "github.com/sagernet/sing/common/tls" + sHTTP "github.com/sagernet/sing/protocol/http" + + mDNS "github.com/miekg/dns" + "golang.org/x/net/http2" +) + +const MimeType = "application/dns-message" + +var _ adapter.DNSTransport = (*HTTPSTransport)(nil) + +func RegisterHTTPS(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteHTTPSDNSServerOptions](registry, C.DNSTypeHTTPS, NewHTTPS) +} + +type HTTPSTransport struct { + dns.TransportAdapter + logger logger.ContextLogger + dialer N.Dialer + destination *url.URL + headers http.Header + transport *http.Transport +} + +func NewHTTPS(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteHTTPSDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewRemoteDialer(ctx, options.RemoteDNSServerOptions) + if err != nil { + return nil, err + } + tlsOptions := common.PtrValueOrDefault(options.TLS) + tlsOptions.Enabled = true + tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + if err != nil { + return nil, err + } + if common.Error(tlsConfig.Config()) == nil && !common.Contains(tlsConfig.NextProtos(), http2.NextProtoTLS) { + tlsConfig.SetNextProtos(append(tlsConfig.NextProtos(), http2.NextProtoTLS)) + } + if !common.Contains(tlsConfig.NextProtos(), "http/1.1") { + tlsConfig.SetNextProtos(append(tlsConfig.NextProtos(), "http/1.1")) + } + headers := options.Headers.Build() + host := headers.Get("Host") + if host != "" { + headers.Del("Host") + } else { + if tlsConfig.ServerName() != "" { + host = tlsConfig.ServerName() + } else { + host = options.Server + } + } + destinationURL := url.URL{ + Scheme: "https", + Host: host, + } + if destinationURL.Host == "" { + destinationURL.Host = options.Server + } + if options.ServerPort != 0 && options.ServerPort != 443 { + destinationURL.Host = net.JoinHostPort(destinationURL.Host, strconv.Itoa(int(options.ServerPort))) + } + path := options.Path + if path == "" { + path = "/dns-query" + } + err = sHTTP.URLSetPath(&destinationURL, path) + if err != nil { + return nil, err + } + serverAddr := options.ServerOptions.Build() + if serverAddr.Port == 0 { + serverAddr.Port = 443 + } + return NewHTTPSRaw( + dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeHTTPS, tag, options.RemoteDNSServerOptions), + logger, + transportDialer, + &destinationURL, + headers, + serverAddr, + tlsConfig, + ), nil +} + +func NewHTTPSRaw( + adapter dns.TransportAdapter, + logger log.ContextLogger, + dialer N.Dialer, + destination *url.URL, + headers http.Header, + serverAddr M.Socksaddr, + tlsConfig tls.Config, +) *HTTPSTransport { + var transport *http.Transport + if tlsConfig != nil { + transport = &http.Transport{ + ForceAttemptHTTP2: true, + DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + tcpConn, hErr := dialer.DialContext(ctx, network, serverAddr) + if hErr != nil { + return nil, hErr + } + tlsConn, hErr := aTLS.ClientHandshake(ctx, tcpConn, tlsConfig) + if hErr != nil { + tcpConn.Close() + return nil, hErr + } + return tlsConn, nil + }, + } + } else { + transport = &http.Transport{ + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer.DialContext(ctx, network, serverAddr) + }, + } + } + return &HTTPSTransport{ + TransportAdapter: adapter, + logger: logger, + dialer: dialer, + destination: destination, + headers: headers, + transport: transport, + } +} + +func (t *HTTPSTransport) Reset() { + t.transport.CloseIdleConnections() + t.transport = t.transport.Clone() +} + +func (t *HTTPSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + exMessage := *message + exMessage.Id = 0 + exMessage.Compress = true + requestBuffer := buf.NewSize(1 + message.Len()) + rawMessage, err := exMessage.PackBuffer(requestBuffer.FreeBytes()) + if err != nil { + requestBuffer.Release() + return nil, err + } + request, err := http.NewRequestWithContext(ctx, http.MethodPost, t.destination.String(), bytes.NewReader(rawMessage)) + if err != nil { + requestBuffer.Release() + return nil, err + } + request.Header = t.headers.Clone() + request.Header.Set("Content-Type", MimeType) + request.Header.Set("Accept", MimeType) + response, err := t.transport.RoundTrip(request) + requestBuffer.Release() + if err != nil { + return nil, err + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + return nil, E.New("unexpected status: ", response.Status) + } + var responseMessage mDNS.Msg + if response.ContentLength > 0 { + responseBuffer := buf.NewSize(int(response.ContentLength)) + _, err = responseBuffer.ReadFullFrom(response.Body, int(response.ContentLength)) + if err != nil { + return nil, err + } + err = responseMessage.Unpack(responseBuffer.Bytes()) + responseBuffer.Release() + } else { + rawMessage, err = io.ReadAll(response.Body) + if err != nil { + return nil, err + } + err = responseMessage.Unpack(rawMessage) + } + if err != nil { + return nil, err + } + return &responseMessage, nil +} diff --git a/dns/transport/local/local.go b/dns/transport/local/local.go new file mode 100644 index 00000000..e5e8aef9 --- /dev/null +++ b/dns/transport/local/local.go @@ -0,0 +1,197 @@ +package local + +import ( + "context" + "math/rand" + "time" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport/hosts" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common/buf" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + mDNS "github.com/miekg/dns" +) + +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewTransport) +} + +var _ adapter.DNSTransport = (*Transport)(nil) + +type Transport struct { + dns.TransportAdapter + hosts *hosts.File + dialer N.Dialer +} + +func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewLocalDialer(ctx, options) + if err != nil { + return nil, err + } + return &Transport{ + TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options), + hosts: hosts.NewFile(hosts.DefaultPath), + dialer: transportDialer, + }, nil +} + +func (t *Transport) Reset() { +} + +func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + question := message.Question[0] + domain := dns.FqdnToDomain(question.Name) + if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA { + addresses := t.hosts.Lookup(domain) + if len(addresses) > 0 { + return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil + } + } + systemConfig := getSystemDNSConfig() + if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) { + return t.exchangeSingleRequest(ctx, systemConfig, message, domain) + } else { + return t.exchangeParallel(ctx, systemConfig, message, domain) + } +} + +func (t *Transport) exchangeSingleRequest(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + var lastErr error + for _, fqdn := range systemConfig.nameList(domain) { + response, err := t.tryOneName(ctx, systemConfig, fqdn, message) + if err != nil { + lastErr = err + continue + } + return response, nil + } + return nil, lastErr +} + +func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + returned := make(chan struct{}) + defer close(returned) + type queryResult struct { + response *mDNS.Msg + err error + } + results := make(chan queryResult) + startRacer := func(ctx context.Context, fqdn string) { + response, err := t.tryOneName(ctx, systemConfig, fqdn, message) + if err == nil { + addresses, _ := dns.MessageToAddresses(response) + if len(addresses) == 0 { + err = E.New(fqdn, ": empty result") + } + } + select { + case results <- queryResult{response, err}: + case <-returned: + } + } + queryCtx, queryCancel := context.WithCancel(ctx) + defer queryCancel() + var nameCount int + for _, fqdn := range systemConfig.nameList(domain) { + nameCount++ + go startRacer(queryCtx, fqdn) + } + var errors []error + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case result := <-results: + if result.err == nil { + return result.response, nil + } + errors = append(errors, result.err) + if len(errors) == nameCount { + return nil, E.Errors(errors...) + } + } + } +} + +func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) { + serverOffset := config.serverOffset() + sLen := uint32(len(config.servers)) + var lastErr error + for i := 0; i < config.attempts; i++ { + for j := uint32(0); j < sLen; j++ { + server := config.servers[(serverOffset+j)%sLen] + question := message.Question[0] + question.Name = fqdn + response, err := t.exchangeOne(ctx, M.ParseSocksaddr(server), question, config.timeout, config.useTCP, config.trustAD) + if err != nil { + lastErr = err + continue + } + return response, nil + } + } + return nil, E.Cause(lastErr, fqdn) +} + +func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) { + var networks []string + if useTCP { + networks = []string{N.NetworkTCP} + } else { + networks = []string{N.NetworkUDP, N.NetworkTCP} + } + request := &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: uint16(rand.Uint32()), + RecursionDesired: true, + AuthenticatedData: ad, + }, + Question: []mDNS.Question{question}, + Compress: true, + } + request.SetEdns0(maxDNSPacketSize, false) + buffer := buf.Get(buf.UDPBufferSize) + defer buf.Put(buffer) + for _, network := range networks { + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) + defer cancel() + conn, err := t.dialer.DialContext(ctx, network, server) + if err != nil { + return nil, err + } + defer conn.Close() + if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() { + conn.SetDeadline(deadline) + } + rawMessage, err := request.PackBuffer(buffer) + if err != nil { + return nil, E.Cause(err, "pack request") + } + _, err = conn.Write(rawMessage) + if err != nil { + return nil, E.Cause(err, "write request") + } + n, err := conn.Read(buffer) + if err != nil { + return nil, E.Cause(err, "read response") + } + var response mDNS.Msg + err = response.Unpack(buffer[:n]) + if err != nil { + return nil, E.Cause(err, "unpack response") + } + if response.Truncated && network == N.NetworkUDP { + continue + } + return &response, nil + } + panic("unexpected") +} diff --git a/dns/transport/local/resolv.go b/dns/transport/local/resolv.go new file mode 100644 index 00000000..5484d0ec --- /dev/null +++ b/dns/transport/local/resolv.go @@ -0,0 +1,146 @@ +package local + +import ( + "os" + "runtime" + "strings" + "sync" + "sync/atomic" + "time" +) + +const ( + // net.maxDNSPacketSize + maxDNSPacketSize = 1232 +) + +type resolverConfig struct { + initOnce sync.Once + ch chan struct{} + lastChecked time.Time + dnsConfig atomic.Pointer[dnsConfig] +} + +var resolvConf resolverConfig + +func getSystemDNSConfig() *dnsConfig { + resolvConf.tryUpdate("/etc/resolv.conf") + return resolvConf.dnsConfig.Load() +} + +func (conf *resolverConfig) init() { + conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf")) + conf.lastChecked = time.Now() + conf.ch = make(chan struct{}, 1) +} + +func (conf *resolverConfig) tryUpdate(name string) { + conf.initOnce.Do(conf.init) + + if conf.dnsConfig.Load().noReload { + return + } + if !conf.tryAcquireSema() { + return + } + defer conf.releaseSema() + + now := time.Now() + if conf.lastChecked.After(now.Add(-5 * time.Second)) { + return + } + conf.lastChecked = now + if runtime.GOOS != "windows" { + var mtime time.Time + if fi, err := os.Stat(name); err == nil { + mtime = fi.ModTime() + } + if mtime.Equal(conf.dnsConfig.Load().mtime) { + return + } + } + dnsConf := dnsReadConfig(name) + conf.dnsConfig.Store(dnsConf) +} + +func (conf *resolverConfig) tryAcquireSema() bool { + select { + case conf.ch <- struct{}{}: + return true + default: + return false + } +} + +func (conf *resolverConfig) releaseSema() { + <-conf.ch +} + +type dnsConfig struct { + servers []string + search []string + ndots int + timeout time.Duration + attempts int + rotate bool + unknownOpt bool + lookup []string + err error + mtime time.Time + soffset uint32 + singleRequest bool + useTCP bool + trustAD bool + noReload bool +} + +func (c *dnsConfig) serverOffset() uint32 { + if c.rotate { + return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start + } + return 0 +} + +func (conf *dnsConfig) nameList(name string) []string { + l := len(name) + rooted := l > 0 && name[l-1] == '.' + if l > 254 || l == 254 && !rooted { + return nil + } + + if rooted { + if avoidDNS(name) { + return nil + } + return []string{name} + } + + hasNdots := strings.Count(name, ".") >= conf.ndots + name += "." + // l++ + + names := make([]string, 0, 1+len(conf.search)) + if hasNdots && !avoidDNS(name) { + names = append(names, name) + } + for _, suffix := range conf.search { + fqdn := name + suffix + if !avoidDNS(fqdn) && len(fqdn) <= 254 { + names = append(names, fqdn) + } + } + if !hasNdots && !avoidDNS(name) { + names = append(names, name) + } + return names +} + +func avoidDNS(name string) bool { + if name == "" { + return true + } + if name[len(name)-1] == '.' { + name = name[:len(name)-1] + } + return strings.HasSuffix(name, ".onion") +} diff --git a/dns/transport/local/resolv_unix.go b/dns/transport/local/resolv_unix.go new file mode 100644 index 00000000..6594ae41 --- /dev/null +++ b/dns/transport/local/resolv_unix.go @@ -0,0 +1,175 @@ +//go:build !windows + +package local + +import ( + "bufio" + "net" + "net/netip" + "os" + "strings" + "time" + _ "unsafe" +) + +func dnsReadConfig(name string) *dnsConfig { + conf := &dnsConfig{ + ndots: 1, + timeout: 5 * time.Second, + attempts: 2, + } + file, err := os.Open(name) + if err != nil { + conf.servers = defaultNS + conf.search = dnsDefaultSearch() + conf.err = err + return conf + } + defer file.Close() + fi, err := file.Stat() + if err == nil { + conf.mtime = fi.ModTime() + } else { + conf.servers = defaultNS + conf.search = dnsDefaultSearch() + conf.err = err + return conf + } + reader := bufio.NewReader(file) + var ( + prefix []byte + line []byte + isPrefix bool + ) + for { + line, isPrefix, err = reader.ReadLine() + if err != nil { + break + } + if isPrefix { + prefix = append(prefix, line...) + continue + } else if len(prefix) > 0 { + line = append(prefix, line...) + prefix = nil + } + if len(line) > 0 && (line[0] == ';' || line[0] == '#') { + continue + } + f := strings.Fields(string(line)) + if len(f) < 1 { + continue + } + switch f[0] { + case "nameserver": + if len(f) > 1 && len(conf.servers) < 3 { + if _, err := netip.ParseAddr(f[1]); err == nil { + conf.servers = append(conf.servers, net.JoinHostPort(f[1], "53")) + } + } + case "domain": + if len(f) > 1 { + conf.search = []string{ensureRooted(f[1])} + } + + case "search": + conf.search = make([]string, 0, len(f)-1) + for i := 1; i < len(f); i++ { + name := ensureRooted(f[i]) + if name == "." { + continue + } + conf.search = append(conf.search, name) + } + + case "options": + for _, s := range f[1:] { + switch { + case strings.HasPrefix(s, "ndots:"): + n, _, _ := dtoi(s[6:]) + if n < 0 { + n = 0 + } else if n > 15 { + n = 15 + } + conf.ndots = n + case strings.HasPrefix(s, "timeout:"): + n, _, _ := dtoi(s[8:]) + if n < 1 { + n = 1 + } + conf.timeout = time.Duration(n) * time.Second + case strings.HasPrefix(s, "attempts:"): + n, _, _ := dtoi(s[9:]) + if n < 1 { + n = 1 + } + conf.attempts = n + case s == "rotate": + conf.rotate = true + case s == "single-request" || s == "single-request-reopen": + conf.singleRequest = true + case s == "use-vc" || s == "usevc" || s == "tcp": + conf.useTCP = true + case s == "trust-ad": + conf.trustAD = true + case s == "edns0": + case s == "no-reload": + conf.noReload = true + default: + conf.unknownOpt = true + } + } + + case "lookup": + conf.lookup = f[1:] + + default: + conf.unknownOpt = true + } + } + if len(conf.servers) == 0 { + conf.servers = defaultNS + } + if len(conf.search) == 0 { + conf.search = dnsDefaultSearch() + } + return conf +} + +//go:linkname defaultNS net.defaultNS +var defaultNS []string + +func dnsDefaultSearch() []string { + hn, err := os.Hostname() + if err != nil { + return nil + } + if i := strings.IndexRune(hn, '.'); i >= 0 && i < len(hn)-1 { + return []string{ensureRooted(hn[i+1:])} + } + return nil +} + +func ensureRooted(s string) string { + if len(s) > 0 && s[len(s)-1] == '.' { + return s + } + return s + "." +} + +const big = 0xFFFFFF + +func dtoi(s string) (n int, i int, ok bool) { + n = 0 + for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + n = n*10 + int(s[i]-'0') + if n >= big { + return big, i, false + } + } + if i == 0 { + return 0, 0, false + } + return n, i, true +} diff --git a/dns/transport/local/resolv_windows.go b/dns/transport/local/resolv_windows.go new file mode 100644 index 00000000..577e7a12 --- /dev/null +++ b/dns/transport/local/resolv_windows.go @@ -0,0 +1,100 @@ +package local + +import ( + "net" + "net/netip" + "os" + "syscall" + "time" + "unsafe" + + "golang.org/x/sys/windows" +) + +func dnsReadConfig(_ string) *dnsConfig { + conf := &dnsConfig{ + ndots: 1, + timeout: 5 * time.Second, + attempts: 2, + } + defer func() { + if len(conf.servers) == 0 { + conf.servers = defaultNS + } + }() + aas, err := adapterAddresses() + if err != nil { + return nil + } + + for _, aa := range aas { + // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. + if aa.OperStatus != windows.IfOperStatusUp { + continue + } + + // Only take interfaces which have at least one gateway + if aa.FirstGatewayAddress == nil { + continue + } + + for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { + sa, err := dns.Address.Sockaddr.Sockaddr() + if err != nil { + continue + } + var ip netip.Addr + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + ip = netip.AddrFrom4([4]byte{sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]}) + case *syscall.SockaddrInet6: + var addr16 [16]byte + copy(addr16[:], sa.Addr[:]) + if addr16[0] == 0xfe && addr16[1] == 0xc0 { + // fec0/10 IPv6 addresses are site local anycast DNS + // addresses Microsoft sets by default if no other + // IPv6 DNS address is set. Site local anycast is + // deprecated since 2004, see + // https://datatracker.ietf.org/doc/html/rfc3879 + continue + } + ip = netip.AddrFrom16(addr16) + default: + // Unexpected type. + continue + } + conf.servers = append(conf.servers, net.JoinHostPort(ip.String(), "53")) + } + } + return conf +} + +//go:linkname defaultNS net.defaultNS +var defaultNS []string + +func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { + var b []byte + l := uint32(15000) // recommended initial size + for { + b = make([]byte, l) + const flags = windows.GAA_FLAG_INCLUDE_PREFIX | windows.GAA_FLAG_INCLUDE_GATEWAYS + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, flags, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + if err == nil { + if l == 0 { + return nil, nil + } + break + } + if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + if l <= uint32(len(b)) { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + } + var aas []*windows.IpAdapterAddresses + for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { + aas = append(aas, aa) + } + return aas, nil +} diff --git a/dns/transport/predefined.go b/dns/transport/predefined.go new file mode 100644 index 00000000..3f112886 --- /dev/null +++ b/dns/transport/predefined.go @@ -0,0 +1,83 @@ +package transport + +import ( + "context" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSTransport = (*PredefinedTransport)(nil) + +func RegisterPredefined(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.PredefinedDNSServerOptions](registry, C.DNSTypePreDefined, NewPredefined) +} + +type PredefinedTransport struct { + dns.TransportAdapter + responses []*predefinedResponse +} + +type predefinedResponse struct { + questions []mDNS.Question + answer *mDNS.Msg +} + +func NewPredefined(ctx context.Context, logger log.ContextLogger, tag string, options option.PredefinedDNSServerOptions) (adapter.DNSTransport, error) { + var responses []*predefinedResponse + for _, response := range options.Responses { + questions, msg, err := response.Build() + if err != nil { + return nil, err + } + responses = append(responses, &predefinedResponse{ + questions: questions, + answer: msg, + }) + } + if len(responses) == 0 { + return nil, E.New("empty predefined responses") + } + return &PredefinedTransport{ + TransportAdapter: dns.NewTransportAdapter(C.DNSTypePreDefined, tag, nil), + responses: responses, + }, nil +} + +func (t *PredefinedTransport) Reset() { +} + +func (t *PredefinedTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + for _, response := range t.responses { + for _, question := range response.questions { + if func() bool { + if question.Name == "" && question.Qtype == mDNS.TypeNone { + return true + } else if question.Name == "" { + return common.Any(message.Question, func(it mDNS.Question) bool { + return it.Qtype == question.Qtype + }) + } else if question.Qtype == mDNS.TypeNone { + return common.Any(message.Question, func(it mDNS.Question) bool { + return it.Name == question.Name + }) + } else { + return common.Contains(message.Question, question) + } + }() { + copyAnswer := *response.answer + copyAnswer.Id = message.Id + copyAnswer.Question = message.Question + return ©Answer, nil + } + } + } + return nil, dns.RCodeNameError +} diff --git a/dns/transport/quic/http3.go b/dns/transport/quic/http3.go new file mode 100644 index 00000000..a5181ae0 --- /dev/null +++ b/dns/transport/quic/http3.go @@ -0,0 +1,167 @@ +package quic + +import ( + "bytes" + "context" + "io" + "net" + "net/http" + "net/url" + "strconv" + + "github.com/sagernet/quic-go" + "github.com/sagernet/quic-go/http3" + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + sHTTP "github.com/sagernet/sing/protocol/http" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSTransport = (*HTTP3Transport)(nil) + +func RegisterHTTP3Transport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteHTTPSDNSServerOptions](registry, C.DNSTypeHTTP3, NewHTTP3) +} + +type HTTP3Transport struct { + dns.TransportAdapter + logger logger.ContextLogger + dialer N.Dialer + destination *url.URL + headers http.Header + transport *http3.Transport +} + +func NewHTTP3(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteHTTPSDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewRemoteDialer(ctx, options.RemoteDNSServerOptions) + if err != nil { + return nil, err + } + tlsOptions := common.PtrValueOrDefault(options.TLS) + tlsOptions.Enabled = true + tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + if err != nil { + return nil, err + } + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + headers := options.Headers.Build() + host := headers.Get("Host") + if host != "" { + headers.Del("Host") + } else { + if tlsConfig.ServerName() != "" { + host = tlsConfig.ServerName() + } else { + host = options.Server + } + } + destinationURL := url.URL{ + Scheme: "https", + Host: host, + } + if destinationURL.Host == "" { + destinationURL.Host = options.Server + } + if options.ServerPort != 0 && options.ServerPort != 443 { + destinationURL.Host = net.JoinHostPort(destinationURL.Host, strconv.Itoa(int(options.ServerPort))) + } + path := options.Path + if path == "" { + path = "/dns-query" + } + err = sHTTP.URLSetPath(&destinationURL, path) + if err != nil { + return nil, err + } + serverAddr := options.ServerOptions.Build() + if serverAddr.Port == 0 { + serverAddr.Port = 443 + } + return &HTTP3Transport{ + TransportAdapter: dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeHTTP3, tag, options.RemoteDNSServerOptions), + logger: logger, + dialer: transportDialer, + destination: &destinationURL, + headers: headers, + transport: &http3.Transport{ + Dial: func(ctx context.Context, addr string, tlsCfg *tls.STDConfig, cfg *quic.Config) (quic.EarlyConnection, error) { + destinationAddr := M.ParseSocksaddr(addr) + conn, dialErr := transportDialer.DialContext(ctx, N.NetworkUDP, destinationAddr) + if dialErr != nil { + return nil, dialErr + } + return quic.DialEarly(ctx, bufio.NewUnbindPacketConn(conn), conn.RemoteAddr(), tlsCfg, cfg) + }, + TLSClientConfig: stdConfig, + }, + }, nil +} + +func (t *HTTP3Transport) Reset() { + t.transport.Close() +} + +func (t *HTTP3Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + exMessage := *message + exMessage.Id = 0 + exMessage.Compress = true + requestBuffer := buf.NewSize(1 + message.Len()) + rawMessage, err := exMessage.PackBuffer(requestBuffer.FreeBytes()) + if err != nil { + requestBuffer.Release() + return nil, err + } + request, err := http.NewRequestWithContext(ctx, http.MethodPost, t.destination.String(), bytes.NewReader(rawMessage)) + if err != nil { + requestBuffer.Release() + return nil, err + } + request.Header = t.headers.Clone() + request.Header.Set("Content-Type", transport.MimeType) + request.Header.Set("Accept", transport.MimeType) + response, err := t.transport.RoundTrip(request) + requestBuffer.Release() + if err != nil { + return nil, err + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + return nil, E.New("unexpected status: ", response.Status) + } + var responseMessage mDNS.Msg + if response.ContentLength > 0 { + responseBuffer := buf.NewSize(int(response.ContentLength)) + _, err = responseBuffer.ReadFullFrom(response.Body, int(response.ContentLength)) + if err != nil { + return nil, err + } + err = responseMessage.Unpack(responseBuffer.Bytes()) + responseBuffer.Release() + } else { + rawMessage, err = io.ReadAll(response.Body) + if err != nil { + return nil, err + } + err = responseMessage.Unpack(rawMessage) + } + if err != nil { + return nil, err + } + return &responseMessage, nil +} diff --git a/dns/transport/quic/quic.go b/dns/transport/quic/quic.go new file mode 100644 index 00000000..d3844c2b --- /dev/null +++ b/dns/transport/quic/quic.go @@ -0,0 +1,174 @@ +package quic + +import ( + "context" + "errors" + "sync" + + "github.com/sagernet/quic-go" + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + sQUIC "github.com/sagernet/sing-quic" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSTransport = (*Transport)(nil) + +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteTLSDNSServerOptions](registry, C.DNSTypeQUIC, NewQUIC) +} + +type Transport struct { + dns.TransportAdapter + ctx context.Context + logger logger.ContextLogger + dialer N.Dialer + serverAddr M.Socksaddr + tlsConfig tls.Config + access sync.Mutex + connection quic.EarlyConnection +} + +func NewQUIC(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteTLSDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewRemoteDialer(ctx, options.RemoteDNSServerOptions) + if err != nil { + return nil, err + } + tlsOptions := common.PtrValueOrDefault(options.TLS) + tlsOptions.Enabled = true + tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + if err != nil { + return nil, err + } + if len(tlsConfig.NextProtos()) == 0 { + tlsConfig.SetNextProtos([]string{"doq"}) + } + serverAddr := options.ServerOptions.Build() + if serverAddr.Port == 0 { + serverAddr.Port = 853 + } + return &Transport{ + TransportAdapter: dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeQUIC, tag, options.RemoteDNSServerOptions), + ctx: ctx, + logger: logger, + dialer: transportDialer, + serverAddr: serverAddr, + tlsConfig: tlsConfig, + }, nil +} + +func (t *Transport) Reset() { + t.access.Lock() + defer t.access.Unlock() + connection := t.connection + if connection != nil { + connection.CloseWithError(0, "") + } +} + +func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + var ( + conn quic.Connection + err error + response *mDNS.Msg + ) + for i := 0; i < 2; i++ { + conn, err = t.openConnection() + if err != nil { + return nil, err + } + response, err = t.exchange(ctx, message, conn) + if err == nil { + return response, nil + } else if !isQUICRetryError(err) { + return nil, err + } else { + conn.CloseWithError(quic.ApplicationErrorCode(0), "") + continue + } + } + return nil, err +} + +func (t *Transport) openConnection() (quic.EarlyConnection, error) { + connection := t.connection + if connection != nil && !common.Done(connection.Context()) { + return connection, nil + } + t.access.Lock() + defer t.access.Unlock() + connection = t.connection + if connection != nil && !common.Done(connection.Context()) { + return connection, nil + } + conn, err := t.dialer.DialContext(t.ctx, N.NetworkUDP, t.serverAddr) + if err != nil { + return nil, err + } + earlyConnection, err := sQUIC.DialEarly( + t.ctx, + bufio.NewUnbindPacketConn(conn), + t.serverAddr.UDPAddr(), + t.tlsConfig, + nil, + ) + if err != nil { + return nil, err + } + t.connection = earlyConnection + return earlyConnection, nil +} + +func (t *Transport) exchange(ctx context.Context, message *mDNS.Msg, conn quic.Connection) (*mDNS.Msg, error) { + stream, err := conn.OpenStreamSync(ctx) + if err != nil { + return nil, err + } + defer stream.Close() + defer stream.CancelRead(0) + err = transport.WriteMessage(stream, 0, message) + if err != nil { + return nil, err + } + return transport.ReadMessage(stream) +} + +// https://github.com/AdguardTeam/dnsproxy/blob/fd1868577652c639cce3da00e12ca548f421baf1/upstream/upstream_quic.go#L394 +func isQUICRetryError(err error) (ok bool) { + var qAppErr *quic.ApplicationError + if errors.As(err, &qAppErr) && qAppErr.ErrorCode == 0 { + return true + } + + var qIdleErr *quic.IdleTimeoutError + if errors.As(err, &qIdleErr) { + return true + } + + var resetErr *quic.StatelessResetError + if errors.As(err, &resetErr) { + return true + } + + var qTransportError *quic.TransportError + if errors.As(err, &qTransportError) && qTransportError.ErrorCode == quic.NoError { + return true + } + + if errors.Is(err, quic.Err0RTTRejected) { + return true + } + + return false +} diff --git a/dns/transport/tcp.go b/dns/transport/tcp.go new file mode 100644 index 00000000..6061585e --- /dev/null +++ b/dns/transport/tcp.go @@ -0,0 +1,99 @@ +package transport + +import ( + "context" + "encoding/binary" + "io" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSTransport = (*TCPTransport)(nil) + +func RegisterTCP(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteDNSServerOptions](registry, C.DNSTypeTCP, NewTCP) +} + +type TCPTransport struct { + dns.TransportAdapter + dialer N.Dialer + serverAddr M.Socksaddr +} + +func NewTCP(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewRemoteDialer(ctx, options) + if err != nil { + return nil, err + } + serverAddr := options.ServerOptions.Build() + if serverAddr.Port == 0 { + serverAddr.Port = 53 + } + return &TCPTransport{ + TransportAdapter: dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeTCP, tag, options), + dialer: transportDialer, + serverAddr: serverAddr, + }, nil +} + +func (t *TCPTransport) Reset() { +} + +func (t *TCPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + conn, err := t.dialer.DialContext(ctx, N.NetworkTCP, t.serverAddr) + if err != nil { + return nil, err + } + defer conn.Close() + err = WriteMessage(conn, 0, message) + if err != nil { + return nil, err + } + return ReadMessage(conn) +} + +func ReadMessage(reader io.Reader) (*mDNS.Msg, error) { + var responseLen uint16 + err := binary.Read(reader, binary.BigEndian, &responseLen) + if err != nil { + return nil, err + } + if responseLen < 10 { + return nil, mDNS.ErrShortRead + } + buffer := buf.NewSize(int(responseLen)) + defer buffer.Release() + _, err = buffer.ReadFullFrom(reader, int(responseLen)) + if err != nil { + return nil, err + } + var message mDNS.Msg + err = message.Unpack(buffer.Bytes()) + return &message, err +} + +func WriteMessage(writer io.Writer, messageId uint16, message *mDNS.Msg) error { + requestLen := message.Len() + buffer := buf.NewSize(3 + requestLen) + defer buffer.Release() + common.Must(binary.Write(buffer, binary.BigEndian, uint16(requestLen))) + exMessage := *message + exMessage.Id = messageId + exMessage.Compress = true + rawMessage, err := exMessage.PackBuffer(buffer.FreeBytes()) + if err != nil { + return err + } + buffer.Truncate(2 + len(rawMessage)) + return common.Error(writer.Write(buffer.Bytes())) +} diff --git a/dns/transport/tls.go b/dns/transport/tls.go new file mode 100644 index 00000000..28fa885a --- /dev/null +++ b/dns/transport/tls.go @@ -0,0 +1,115 @@ +package transport + +import ( + "context" + "sync" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/x/list" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSTransport = (*TLSTransport)(nil) + +func RegisterTLS(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteTLSDNSServerOptions](registry, C.DNSTypeTLS, NewTLS) +} + +type TLSTransport struct { + dns.TransportAdapter + logger logger.ContextLogger + dialer N.Dialer + serverAddr M.Socksaddr + tlsConfig tls.Config + access sync.Mutex + connections list.List[*tlsDNSConn] +} + +type tlsDNSConn struct { + tls.Conn + queryId uint16 +} + +func NewTLS(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteTLSDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewRemoteDialer(ctx, options.RemoteDNSServerOptions) + if err != nil { + return nil, err + } + tlsOptions := common.PtrValueOrDefault(options.TLS) + tlsOptions.Enabled = true + tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + if err != nil { + return nil, err + } + serverAddr := options.ServerOptions.Build() + if serverAddr.Port == 0 { + serverAddr.Port = 853 + } + return &TLSTransport{ + TransportAdapter: dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeTLS, tag, options.RemoteDNSServerOptions), + logger: logger, + dialer: transportDialer, + serverAddr: serverAddr, + tlsConfig: tlsConfig, + }, nil +} + +func (t *TLSTransport) Reset() { + t.access.Lock() + defer t.access.Unlock() + for connection := t.connections.Front(); connection != nil; connection = connection.Next() { + connection.Value.Close() + } + t.connections.Init() +} + +func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + t.access.Lock() + conn := t.connections.PopFront() + t.access.Unlock() + if conn != nil { + response, err := t.exchange(message, conn) + if err == nil { + return response, nil + } + } + tcpConn, err := t.dialer.DialContext(ctx, N.NetworkTCP, t.serverAddr) + if err != nil { + return nil, err + } + tlsConn, err := tls.ClientHandshake(ctx, tcpConn, t.tlsConfig) + if err != nil { + tcpConn.Close() + return nil, err + } + return t.exchange(message, &tlsDNSConn{Conn: tlsConn}) +} + +func (t *TLSTransport) exchange(message *mDNS.Msg, conn *tlsDNSConn) (*mDNS.Msg, error) { + conn.queryId++ + err := WriteMessage(conn, conn.queryId, message) + if err != nil { + conn.Close() + return nil, E.Cause(err, "write request") + } + response, err := ReadMessage(conn) + if err != nil { + conn.Close() + return nil, E.Cause(err, "read response") + } + t.access.Lock() + t.connections.PushBack(conn) + t.access.Unlock() + return response, nil +} diff --git a/dns/transport/udp.go b/dns/transport/udp.go new file mode 100644 index 00000000..5099c6f6 --- /dev/null +++ b/dns/transport/udp.go @@ -0,0 +1,223 @@ +package transport + +import ( + "context" + "net" + "os" + "sync" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + mDNS "github.com/miekg/dns" +) + +var _ adapter.DNSTransport = (*UDPTransport)(nil) + +func RegisterUDP(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteDNSServerOptions](registry, C.DNSTypeUDP, NewUDP) +} + +type UDPTransport struct { + dns.TransportAdapter + logger logger.ContextLogger + dialer N.Dialer + serverAddr M.Socksaddr + udpSize int + tcpTransport *TCPTransport + access sync.Mutex + conn *dnsConnection + done chan struct{} +} + +func NewUDP(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewRemoteDialer(ctx, options) + if err != nil { + return nil, err + } + serverAddr := options.ServerOptions.Build() + if serverAddr.Port == 0 { + serverAddr.Port = 53 + } + return NewUDPRaw(logger, dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeUDP, tag, options), transportDialer, serverAddr), nil +} + +func NewUDPRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer N.Dialer, serverAddr M.Socksaddr) *UDPTransport { + return &UDPTransport{ + TransportAdapter: adapter, + logger: logger, + dialer: dialer, + serverAddr: serverAddr, + udpSize: 512, + tcpTransport: &TCPTransport{ + dialer: dialer, + serverAddr: serverAddr, + }, + done: make(chan struct{}), + } +} + +func (t *UDPTransport) Reset() { + t.access.Lock() + defer t.access.Unlock() + close(t.done) + t.done = make(chan struct{}) +} + +func (t *UDPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + response, err := t.exchange(ctx, message) + if err != nil { + return nil, err + } + if response.Truncated { + t.logger.InfoContext(ctx, "response truncated, retrying with TCP") + return t.tcpTransport.Exchange(ctx, message) + } + return response, nil +} + +func (t *UDPTransport) exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + conn, err := t.open(ctx) + if err != nil { + return nil, err + } + if edns0Opt := message.IsEdns0(); edns0Opt != nil { + if udpSize := int(edns0Opt.UDPSize()); udpSize > t.udpSize { + t.udpSize = udpSize + } + } + buffer := buf.NewSize(1 + message.Len()) + defer buffer.Release() + exMessage := *message + exMessage.Compress = true + messageId := message.Id + callback := &dnsCallback{ + done: make(chan struct{}), + } + conn.access.Lock() + conn.queryId++ + exMessage.Id = conn.queryId + conn.callbacks[exMessage.Id] = callback + conn.access.Unlock() + defer func() { + conn.access.Lock() + delete(conn.callbacks, messageId) + conn.access.Unlock() + callback.access.Lock() + select { + case <-callback.done: + default: + close(callback.done) + } + callback.access.Unlock() + }() + rawMessage, err := exMessage.PackBuffer(buffer.FreeBytes()) + if err != nil { + return nil, err + } + _, err = conn.Write(rawMessage) + if err != nil { + conn.Close(err) + return nil, err + } + select { + case <-callback.done: + callback.message.Id = messageId + return callback.message, nil + case <-conn.done: + return nil, conn.err + case <-t.done: + return nil, os.ErrClosed + case <-ctx.Done(): + conn.Close(ctx.Err()) + return nil, ctx.Err() + } +} + +func (t *UDPTransport) open(ctx context.Context) (*dnsConnection, error) { + t.access.Lock() + defer t.access.Unlock() + if t.conn != nil { + select { + case <-t.conn.done: + default: + return t.conn, nil + } + } + conn, err := t.dialer.DialContext(ctx, N.NetworkUDP, t.serverAddr) + if err != nil { + return nil, err + } + dnsConn := &dnsConnection{ + Conn: conn, + done: make(chan struct{}), + callbacks: make(map[uint16]*dnsCallback), + } + go t.recvLoop(dnsConn) + t.conn = dnsConn + return dnsConn, nil +} + +func (t *UDPTransport) recvLoop(conn *dnsConnection) { + for { + buffer := buf.NewSize(t.udpSize) + _, err := buffer.ReadOnceFrom(conn) + if err != nil { + buffer.Release() + conn.Close(err) + return + } + var message mDNS.Msg + err = message.Unpack(buffer.Bytes()) + buffer.Release() + if err != nil { + conn.Close(err) + return + } + conn.access.RLock() + callback, loaded := conn.callbacks[message.Id] + conn.access.RUnlock() + if !loaded { + continue + } + callback.access.Lock() + select { + case <-callback.done: + default: + callback.message = &message + close(callback.done) + } + callback.access.Unlock() + } +} + +type dnsConnection struct { + net.Conn + access sync.RWMutex + done chan struct{} + closeOnce sync.Once + err error + queryId uint16 + callbacks map[uint16]*dnsCallback +} + +func (c *dnsConnection) Close(err error) { + c.closeOnce.Do(func() { + close(c.done) + c.err = err + }) + c.Conn.Close() +} + +type dnsCallback struct { + access sync.Mutex + message *mDNS.Msg + done chan struct{} +} diff --git a/dns/transport_adapter.go b/dns/transport_adapter.go new file mode 100644 index 00000000..02c84621 --- /dev/null +++ b/dns/transport_adapter.go @@ -0,0 +1,70 @@ +package dns + +import ( + "net/netip" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" +) + +var _ adapter.LegacyDNSTransport = (*TransportAdapter)(nil) + +type TransportAdapter struct { + transportType string + transportTag string + dependencies []string + strategy C.DomainStrategy + clientSubnet netip.Prefix +} + +func NewTransportAdapter(transportType string, transportTag string, dependencies []string) TransportAdapter { + return TransportAdapter{ + transportType: transportType, + transportTag: transportTag, + dependencies: dependencies, + } +} + +func NewTransportAdapterWithLocalOptions(transportType string, transportTag string, localOptions option.LocalDNSServerOptions) TransportAdapter { + return TransportAdapter{ + transportType: transportType, + transportTag: transportTag, + strategy: C.DomainStrategy(localOptions.LegacyStrategy), + clientSubnet: localOptions.LegacyClientSubnet, + } +} + +func NewTransportAdapterWithRemoteOptions(transportType string, transportTag string, remoteOptions option.RemoteDNSServerOptions) TransportAdapter { + var dependencies []string + if remoteOptions.AddressResolver != "" { + dependencies = []string{remoteOptions.AddressResolver} + } + return TransportAdapter{ + transportType: transportType, + transportTag: transportTag, + dependencies: dependencies, + strategy: C.DomainStrategy(remoteOptions.LegacyStrategy), + clientSubnet: remoteOptions.LegacyClientSubnet, + } +} + +func (a *TransportAdapter) Type() string { + return a.transportType +} + +func (a *TransportAdapter) Tag() string { + return a.transportTag +} + +func (a *TransportAdapter) Dependencies() []string { + return a.dependencies +} + +func (a *TransportAdapter) LegacyStrategy() C.DomainStrategy { + return a.strategy +} + +func (a *TransportAdapter) LegacyClientSubnet() netip.Prefix { + return a.clientSubnet +} diff --git a/dns/transport_dialer.go b/dns/transport_dialer.go new file mode 100644 index 00000000..14e1188d --- /dev/null +++ b/dns/transport_dialer.go @@ -0,0 +1,93 @@ +package dns + +import ( + "context" + "net" + "time" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/dialer" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" +) + +func NewLocalDialer(ctx context.Context, options option.LocalDNSServerOptions) (N.Dialer, error) { + if options.LegacyDefaultDialer { + return dialer.NewDefaultOutbound(ctx), nil + } else { + return dialer.New(ctx, options.DialerOptions) + } +} + +func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions) (N.Dialer, error) { + transportDialer, err := NewLocalDialer(ctx, options.LocalDNSServerOptions) + if err != nil { + return nil, err + } + if options.AddressResolver != "" { + transport := service.FromContext[adapter.DNSTransportManager](ctx) + resolverTransport, loaded := transport.Transport(options.AddressResolver) + if !loaded { + return nil, E.New("address resolver not found: ", options.AddressResolver) + } + transportDialer = NewTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.AddressStrategy), time.Duration(options.AddressFallbackDelay)) + } else if M.IsDomainName(options.Server) { + return nil, E.New("missing address resolver for server: ", options.Server) + } + return transportDialer, nil +} + +type TransportDialer struct { + dialer N.Dialer + dnsRouter adapter.DNSRouter + transport adapter.DNSTransport + strategy C.DomainStrategy + fallbackDelay time.Duration +} + +func NewTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) *TransportDialer { + return &TransportDialer{ + dialer, + dnsRouter, + transport, + strategy, + fallbackDelay, + } +} + +func (d *TransportDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + if destination.IsIP() { + return d.dialer.DialContext(ctx, network, destination) + } + addresses, err := d.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{ + Transport: d.transport, + Strategy: d.strategy, + }) + if err != nil { + return nil, err + } + return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay) +} + +func (d *TransportDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + if destination.IsIP() { + return d.dialer.ListenPacket(ctx, destination) + } + addresses, err := d.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{ + Transport: d.transport, + Strategy: d.strategy, + }) + if err != nil { + return nil, err + } + conn, _, err := N.ListenSerial(ctx, d.dialer, destination, addresses) + return conn, err +} + +func (d *TransportDialer) Upstream() any { + return d.dialer +} diff --git a/dns/transport_manager.go b/dns/transport_manager.go new file mode 100644 index 00000000..4497923b --- /dev/null +++ b/dns/transport_manager.go @@ -0,0 +1,288 @@ +package dns + +import ( + "context" + "io" + "os" + "strings" + "sync" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/taskmonitor" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" +) + +var _ adapter.DNSTransportManager = (*TransportManager)(nil) + +type TransportManager struct { + logger log.ContextLogger + registry adapter.DNSTransportRegistry + outbound adapter.OutboundManager + defaultTag string + access sync.RWMutex + started bool + stage adapter.StartStage + transports []adapter.DNSTransport + transportByTag map[string]adapter.DNSTransport + dependByTag map[string][]string + defaultTransport adapter.DNSTransport + defaultTransportFallback adapter.DNSTransport + fakeIPTransport adapter.FakeIPTransport +} + +func NewTransportManager(logger logger.ContextLogger, registry adapter.DNSTransportRegistry, outbound adapter.OutboundManager, defaultTag string) *TransportManager { + return &TransportManager{ + logger: logger, + registry: registry, + outbound: outbound, + defaultTag: defaultTag, + transportByTag: make(map[string]adapter.DNSTransport), + dependByTag: make(map[string][]string), + } +} + +func (m *TransportManager) Initialize(defaultTransportFallback adapter.DNSTransport) { + m.defaultTransportFallback = defaultTransportFallback +} + +func (m *TransportManager) Start(stage adapter.StartStage) error { + m.access.Lock() + if m.started && m.stage >= stage { + panic("already started") + } + m.started = true + m.stage = stage + outbounds := m.transports + m.access.Unlock() + if stage == adapter.StartStateStart { + return m.startTransports(m.transports) + } else { + for _, outbound := range outbounds { + err := adapter.LegacyStart(outbound, stage) + if err != nil { + return E.Cause(err, stage, " dns/", outbound.Type(), "[", outbound.Tag(), "]") + } + } + } + return nil +} + +func (m *TransportManager) startTransports(transports []adapter.DNSTransport) error { + monitor := taskmonitor.New(m.logger, C.StartTimeout) + started := make(map[string]bool) + for { + canContinue := false + startOne: + for _, transportToStart := range transports { + transportTag := transportToStart.Tag() + if started[transportTag] { + continue + } + dependencies := transportToStart.Dependencies() + for _, dependency := range dependencies { + if !started[dependency] { + continue startOne + } + } + started[transportTag] = true + canContinue = true + if starter, isStarter := transportToStart.(adapter.Lifecycle); isStarter { + monitor.Start("start dns/", transportToStart.Type(), "[", transportTag, "]") + err := starter.Start(adapter.StartStateStart) + monitor.Finish() + if err != nil { + return E.Cause(err, "start dns/", transportToStart.Type(), "[", transportTag, "]") + } + } + } + if len(started) == len(transports) { + break + } + if canContinue { + continue + } + currentTransport := common.Find(transports, func(it adapter.DNSTransport) bool { + return !started[it.Tag()] + }) + var lintTransport func(oTree []string, oCurrent adapter.DNSTransport) error + lintTransport = func(oTree []string, oCurrent adapter.DNSTransport) error { + problemTransportTag := common.Find(oCurrent.Dependencies(), func(it string) bool { + return !started[it] + }) + if common.Contains(oTree, problemTransportTag) { + return E.New("circular server dependency: ", strings.Join(oTree, " -> "), " -> ", problemTransportTag) + } + m.access.Lock() + problemTransport := m.transportByTag[problemTransportTag] + m.access.Unlock() + if problemTransport == nil { + return E.New("dependency[", problemTransportTag, "] not found for server[", oCurrent.Tag(), "]") + } + return lintTransport(append(oTree, problemTransportTag), problemTransport) + } + return lintTransport([]string{currentTransport.Tag()}, currentTransport) + } + return nil +} + +func (m *TransportManager) Close() error { + monitor := taskmonitor.New(m.logger, C.StopTimeout) + m.access.Lock() + if !m.started { + m.access.Unlock() + return nil + } + m.started = false + transports := m.transports + m.transports = nil + m.access.Unlock() + var err error + for _, transport := range transports { + if closer, isCloser := transport.(io.Closer); isCloser { + monitor.Start("close server/", transport.Type(), "[", transport.Tag(), "]") + err = E.Append(err, closer.Close(), func(err error) error { + return E.Cause(err, "close server/", transport.Type(), "[", transport.Tag(), "]") + }) + monitor.Finish() + } + } + return nil +} + +func (m *TransportManager) Transports() []adapter.DNSTransport { + m.access.RLock() + defer m.access.RUnlock() + return m.transports +} + +func (m *TransportManager) Transport(tag string) (adapter.DNSTransport, bool) { + m.access.RLock() + outbound, found := m.transportByTag[tag] + m.access.RUnlock() + return outbound, found +} + +func (m *TransportManager) Default() adapter.DNSTransport { + m.access.RLock() + defer m.access.RUnlock() + if m.defaultTransport != nil { + return m.defaultTransport + } else { + return m.defaultTransportFallback + } +} + +func (m *TransportManager) FakeIP() adapter.FakeIPTransport { + m.access.RLock() + defer m.access.RUnlock() + return m.fakeIPTransport +} + +func (m *TransportManager) Remove(tag string) error { + m.access.Lock() + defer m.access.Unlock() + transport, found := m.transportByTag[tag] + if !found { + return os.ErrInvalid + } + delete(m.transportByTag, tag) + index := common.Index(m.transports, func(it adapter.DNSTransport) bool { + return it == transport + }) + if index == -1 { + panic("invalid inbound index") + } + m.transports = append(m.transports[:index], m.transports[index+1:]...) + started := m.started + if m.defaultTransport == transport { + if len(m.transports) > 0 { + nextTransport := m.transports[0] + if nextTransport.Type() != C.DNSTypeFakeIP { + return E.New("default server cannot be fakeip") + } + m.defaultTransport = nextTransport + m.logger.Info("updated default server to ", m.defaultTransport.Tag()) + } else { + m.defaultTransport = nil + } + } + dependBy := m.dependByTag[tag] + if len(dependBy) > 0 { + return E.New("server[", tag, "] is depended by ", strings.Join(dependBy, ", ")) + } + dependencies := transport.Dependencies() + for _, dependency := range dependencies { + if len(m.dependByTag[dependency]) == 1 { + delete(m.dependByTag, dependency) + } else { + m.dependByTag[dependency] = common.Filter(m.dependByTag[dependency], func(it string) bool { + return it != tag + }) + } + } + if started { + transport.Reset() + } + return nil +} + +func (m *TransportManager) Create(ctx context.Context, logger log.ContextLogger, tag string, transportType string, options any) error { + if tag == "" { + return os.ErrInvalid + } + transport, err := m.registry.CreateDNSTransport(ctx, logger, tag, transportType, options) + if err != nil { + return err + } + m.access.Lock() + defer m.access.Unlock() + if m.started { + for _, stage := range adapter.ListStartStages { + err = adapter.LegacyStart(transport, stage) + if err != nil { + return E.Cause(err, stage, " dns/", transport.Type(), "[", transport.Tag(), "]") + } + } + } + if existsTransport, loaded := m.transportByTag[tag]; loaded { + if m.started { + err = common.Close(existsTransport) + if err != nil { + return E.Cause(err, "close dns/", existsTransport.Type(), "[", existsTransport.Tag(), "]") + } + } + existsIndex := common.Index(m.transports, func(it adapter.DNSTransport) bool { + return it == existsTransport + }) + if existsIndex == -1 { + panic("invalid inbound index") + } + m.transports = append(m.transports[:existsIndex], m.transports[existsIndex+1:]...) + } + m.transports = append(m.transports, transport) + m.transportByTag[tag] = transport + dependencies := transport.Dependencies() + for _, dependency := range dependencies { + m.dependByTag[dependency] = append(m.dependByTag[dependency], tag) + } + if tag == m.defaultTag || (m.defaultTag == "" && m.defaultTransport == nil) { + if transport.Type() == C.DNSTypeFakeIP { + return E.New("default server cannot be fakeip") + } + m.defaultTransport = transport + if m.started { + m.logger.Info("updated default server to ", transport.Tag()) + } + } + if transport.Type() == C.DNSTypeFakeIP { + if m.fakeIPTransport != nil { + return E.New("multiple fakeip server are not supported") + } + m.fakeIPTransport = transport.(adapter.FakeIPTransport) + } + return nil +} diff --git a/dns/transport_registry.go b/dns/transport_registry.go new file mode 100644 index 00000000..d838158b --- /dev/null +++ b/dns/transport_registry.go @@ -0,0 +1,72 @@ +package dns + +import ( + "context" + "sync" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" +) + +type TransportConstructorFunc[T any] func(ctx context.Context, logger log.ContextLogger, tag string, options T) (adapter.DNSTransport, error) + +func RegisterTransport[Options any](registry *TransportRegistry, transportType string, constructor TransportConstructorFunc[Options]) { + registry.register(transportType, func() any { + return new(Options) + }, func(ctx context.Context, logger log.ContextLogger, tag string, rawOptions any) (adapter.DNSTransport, error) { + var options *Options + if rawOptions != nil { + options = rawOptions.(*Options) + } + return constructor(ctx, logger, tag, common.PtrValueOrDefault(options)) + }) +} + +var _ adapter.DNSTransportRegistry = (*TransportRegistry)(nil) + +type ( + optionsConstructorFunc func() any + constructorFunc func(ctx context.Context, logger log.ContextLogger, tag string, options any) (adapter.DNSTransport, error) +) + +type TransportRegistry struct { + access sync.Mutex + optionsType map[string]optionsConstructorFunc + constructors map[string]constructorFunc +} + +func NewTransportRegistry() *TransportRegistry { + return &TransportRegistry{ + optionsType: make(map[string]optionsConstructorFunc), + constructors: make(map[string]constructorFunc), + } +} + +func (r *TransportRegistry) CreateOptions(transportType string) (any, bool) { + r.access.Lock() + defer r.access.Unlock() + optionsConstructor, loaded := r.optionsType[transportType] + if !loaded { + return nil, false + } + return optionsConstructor(), true +} + +func (r *TransportRegistry) CreateDNSTransport(ctx context.Context, logger log.ContextLogger, tag string, transportType string, options any) (adapter.DNSTransport, error) { + r.access.Lock() + defer r.access.Unlock() + constructor, loaded := r.constructors[transportType] + if !loaded { + return nil, E.New("transport type not found: " + transportType) + } + return constructor(ctx, logger, tag, options) +} + +func (r *TransportRegistry) register(transportType string, optionsConstructor optionsConstructorFunc, constructor constructorFunc) { + r.access.Lock() + defer r.access.Unlock() + r.optionsType[transportType] = optionsConstructor + r.constructors[transportType] = constructor +} diff --git a/experimental/clashapi/dns.go b/experimental/clashapi/dns.go index 2a21a7c1..4f850f82 100644 --- a/experimental/clashapi/dns.go +++ b/experimental/clashapi/dns.go @@ -13,13 +13,13 @@ import ( "github.com/miekg/dns" ) -func dnsRouter(router adapter.Router) http.Handler { +func dnsRouter(router adapter.DNSRouter) http.Handler { r := chi.NewRouter() r.Get("/query", queryDNS(router)) return r } -func queryDNS(router adapter.Router) func(w http.ResponseWriter, r *http.Request) { +func queryDNS(router adapter.DNSRouter) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") qTypeStr := r.URL.Query().Get("type") @@ -39,7 +39,7 @@ func queryDNS(router adapter.Router) func(w http.ResponseWriter, r *http.Request msg := dns.Msg{} msg.SetQuestion(dns.Fqdn(name), qType) - resp, err := router.Exchange(ctx, &msg) + resp, err := router.Exchange(ctx, &msg, adapter.DNSQueryOptions{}) if err != nil { render.Status(r, http.StatusInternalServerError) render.JSON(w, r, newError(err.Error())) diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go index efe2ce36..d01e180a 100644 --- a/experimental/clashapi/server.go +++ b/experimental/clashapi/server.go @@ -42,6 +42,7 @@ var _ adapter.ClashServer = (*Server)(nil) type Server struct { ctx context.Context router adapter.Router + dnsRouter adapter.DNSRouter outbound adapter.OutboundManager endpoint adapter.EndpointManager logger log.Logger @@ -62,11 +63,12 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op trafficManager := trafficontrol.NewManager() chiRouter := chi.NewRouter() s := &Server{ - ctx: ctx, - router: service.FromContext[adapter.Router](ctx), - outbound: service.FromContext[adapter.OutboundManager](ctx), - endpoint: service.FromContext[adapter.EndpointManager](ctx), - logger: logFactory.NewLogger("clash-api"), + ctx: ctx, + router: service.FromContext[adapter.Router](ctx), + dnsRouter: service.FromContext[adapter.DNSRouter](ctx), + outbound: service.FromContext[adapter.OutboundManager](ctx), + endpoint: service.FromContext[adapter.EndpointManager](ctx), + logger: logFactory.NewLogger("clash-api"), httpServer: &http.Server{ Addr: options.ExternalController, Handler: chiRouter, @@ -121,7 +123,7 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op r.Mount("/script", scriptRouter()) r.Mount("/profile", profileRouter()) r.Mount("/cache", cacheRouter(ctx)) - r.Mount("/dns", dnsRouter(s.router)) + r.Mount("/dns", dnsRouter(s.dnsRouter)) s.setupMetaAPI(r) }) @@ -221,7 +223,7 @@ func (s *Server) SetMode(newMode string) { default: } } - s.router.ClearDNSCache() + s.dnsRouter.ClearCache() cacheFile := service.FromContext[adapter.CacheFile](s.ctx) if cacheFile != nil { err := cacheFile.StoreMode(newMode) diff --git a/experimental/deprecated/constants.go b/experimental/deprecated/constants.go index 68aa9aca..bf648365 100644 --- a/experimental/deprecated/constants.go +++ b/experimental/deprecated/constants.go @@ -146,6 +146,21 @@ var OptionTUNGSO = Note{ EnvName: "TUN_GSO", } +var OptionLegacyDNSTransport = Note{ + Name: "legacy-dns-transport", + Description: "legacy DNS transport", + DeprecatedVersion: "1.12.0", + ScheduledVersion: "1.14.0", + EnvName: "LEGACY_DNS_TRANSPORT", +} + +var OptionLegacyDNSFakeIPOptions = Note{ + Name: "legacy-dns-fakeip-options", + Description: "legacy DNS fakeip options", + DeprecatedVersion: "1.12.0", + ScheduledVersion: "1.14.0", +} + var Options = []Note{ OptionBadMatchSource, OptionGEOIP, diff --git a/experimental/libbox/config.go b/experimental/libbox/config.go index 159fd8f6..603d8b6d 100644 --- a/experimental/libbox/config.go +++ b/experimental/libbox/config.go @@ -9,8 +9,11 @@ import ( "github.com/sagernet/sing-box" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/process" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/include" + "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common/control" @@ -21,6 +24,18 @@ import ( "github.com/sagernet/sing/service" ) +func BaseContext(platformInterface PlatformInterface) context.Context { + dnsRegistry := include.DNSTransportRegistry() + if platformInterface != nil { + if localTransport := platformInterface.LocalDNSTransport(); localTransport != nil { + dns.RegisterTransport[option.LocalDNSServerOptions](dnsRegistry, C.DNSTypeLocal, func(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) { + return newPlatformTransport(localTransport, tag, options), nil + }) + } + } + return box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), dnsRegistry) +} + func parseConfig(ctx context.Context, configContent string) (option.Options, error) { options, err := json.UnmarshalExtendedContext[option.Options](ctx, []byte(configContent)) if err != nil { @@ -30,7 +45,7 @@ func parseConfig(ctx context.Context, configContent string) (option.Options, err } func CheckConfig(configContent string) error { - ctx := box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()) + ctx := BaseContext(nil) options, err := parseConfig(ctx, configContent) if err != nil { return err @@ -131,7 +146,7 @@ func (s *platformInterfaceStub) SendNotification(notification *platform.Notifica } func FormatConfig(configContent string) (*StringBox, error) { - options, err := parseConfig(box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()), configContent) + options, err := parseConfig(BaseContext(nil), configContent) if err != nil { return nil, err } diff --git a/experimental/libbox/dns.go b/experimental/libbox/dns.go index a46d9b42..a7ccd2a2 100644 --- a/experimental/libbox/dns.go +++ b/experimental/libbox/dns.go @@ -6,7 +6,10 @@ import ( "strings" "syscall" - "github.com/sagernet/sing-dns" + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -21,118 +24,80 @@ type LocalDNSTransport interface { Exchange(ctx *ExchangeContext, message []byte) error } -func RegisterLocalDNSTransport(transport LocalDNSTransport) { - if transport == nil { - dns.RegisterTransport([]string{"local"}, func(options dns.TransportOptions) (dns.Transport, error) { - return dns.NewLocalTransport(options), nil - }) - } else { - dns.RegisterTransport([]string{"local"}, func(options dns.TransportOptions) (dns.Transport, error) { - return &platformLocalDNSTransport{ - iif: transport, - }, nil - }) - } -} +var _ adapter.DNSTransport = (*platformTransport)(nil) -var _ dns.Transport = (*platformLocalDNSTransport)(nil) - -type platformLocalDNSTransport struct { +type platformTransport struct { + dns.TransportAdapter iif LocalDNSTransport } -func (p *platformLocalDNSTransport) Name() string { - return "local" -} - -func (p *platformLocalDNSTransport) Start() error { - return nil -} - -func (p *platformLocalDNSTransport) Reset() { -} - -func (p *platformLocalDNSTransport) Close() error { - return nil -} - -func (p *platformLocalDNSTransport) Raw() bool { - return p.iif.Raw() -} - -func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { - messageBytes, err := message.Pack() - if err != nil { - return nil, err +func newPlatformTransport(iif LocalDNSTransport, tag string, options option.LocalDNSServerOptions) *platformTransport { + return &platformTransport{ + TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options), + iif: iif, } +} + +func (p *platformTransport) Reset() { +} + +func (p *platformTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { response := &ExchangeContext{ context: ctx, } - var responseMessage *mDNS.Msg - var group task.Group - group.Append0(func(ctx context.Context) error { - err = p.iif.Exchange(response, messageBytes) + if p.iif.Raw() { + messageBytes, err := message.Pack() if err != nil { - return err + return nil, err } - if response.error != nil { - return response.error - } - responseMessage = &response.message - return nil - }) - err = group.Run(ctx) - if err != nil { - return nil, err - } - return responseMessage, nil -} - -func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) { - var network string - switch strategy { - case dns.DomainStrategyUseIPv4: - network = "ip4" - case dns.DomainStrategyPreferIPv6: - network = "ip6" - default: - network = "ip" - } - response := &ExchangeContext{ - context: ctx, - } - var responseAddr []netip.Addr - var group task.Group - group.Append0(func(ctx context.Context) error { - err := p.iif.Lookup(response, network, domain) + var responseMessage *mDNS.Msg + var group task.Group + group.Append0(func(ctx context.Context) error { + err = p.iif.Exchange(response, messageBytes) + if err != nil { + return err + } + if response.error != nil { + return response.error + } + responseMessage = &response.message + return nil + }) + err = group.Run(ctx) if err != nil { - return err + return nil, err } - if response.error != nil { - return response.error - } - switch strategy { - case dns.DomainStrategyUseIPv4: - responseAddr = common.Filter(response.addresses, func(it netip.Addr) bool { - return it.Is4() - }) - case dns.DomainStrategyPreferIPv6: - responseAddr = common.Filter(response.addresses, func(it netip.Addr) bool { - return it.Is6() - }) + return responseMessage, nil + } else { + question := message.Question[0] + var network string + switch question.Qtype { + case mDNS.TypeA: + network = "ip4" + case mDNS.TypeAAAA: + network = "ip6" default: - responseAddr = response.addresses + return nil, E.New("only IP queries are supported by current version of Android") } - /*if len(responseAddr) == 0 { - response.error = dns.RCodeSuccess - }*/ - return nil - }) - err := group.Run(ctx) - if err != nil { - return nil, err + var responseAddrs []netip.Addr + var group task.Group + group.Append0(func(ctx context.Context) error { + err := p.iif.Lookup(response, network, question.Name) + if err != nil { + return err + } + if response.error != nil { + return response.error + } + responseAddrs = response.addresses + return nil + }) + err := group.Run(ctx) + if err != nil { + return nil, err + } + return dns.FixedResponse(message.Id, question, responseAddrs, C.DefaultDNSTTL), nil } - return responseAddr, nil } type Func interface { diff --git a/experimental/libbox/platform.go b/experimental/libbox/platform.go index d5951cd3..f0590367 100644 --- a/experimental/libbox/platform.go +++ b/experimental/libbox/platform.go @@ -6,6 +6,7 @@ import ( ) type PlatformInterface interface { + LocalDNSTransport() LocalDNSTransport UsePlatformAutoDetectInterfaceControl() bool AutoDetectInterfaceControl(fd int32) error OpenTun(options TunOptions) (int32, error) diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 8d42d26e..a1e2ec8e 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -18,7 +18,6 @@ import ( "github.com/sagernet/sing-box/experimental/deprecated" "github.com/sagernet/sing-box/experimental/libbox/internal/procfs" "github.com/sagernet/sing-box/experimental/libbox/platform" - "github.com/sagernet/sing-box/include" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-tun" @@ -44,7 +43,7 @@ type BoxService struct { } func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) { - ctx := box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()) + ctx := BaseContext(platformInterface) ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID) service.MustRegister[deprecated.Manager](ctx, new(deprecatedManager)) options, err := parseConfig(ctx, configContent) @@ -192,6 +191,9 @@ func (w *platformInterfaceWrapper) Interfaces() ([]adapter.NetworkInterface, err continue } w.defaultInterfaceAccess.Lock() + // (GOOS=windows) SA4006: this value of `isDefault` is never used + // Why not used? + //nolint:staticcheck isDefault := w.defaultInterface != nil && int(netInterface.Index) == w.defaultInterface.Index w.defaultInterfaceAccess.Unlock() interfaces = append(interfaces, adapter.NetworkInterface{ diff --git a/go.mod b/go.mod index b75ceb34..31af0eb8 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,6 @@ require ( github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.6.1 - github.com/sagernet/sing-dns v0.4.0 github.com/sagernet/sing-mux v0.3.1 github.com/sagernet/sing-quic v0.4.0 github.com/sagernet/sing-shadowsocks v0.2.7 diff --git a/go.sum b/go.sum index 9ffef2d4..0f4ce794 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,6 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4Wk github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA= github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-dns v0.4.0 h1:+mNoOuR3nljjouCH+qMg4zHI1+R9T2ReblGFkZPEndc= -github.com/sagernet/sing-dns v0.4.0/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78= github.com/sagernet/sing-quic v0.4.0 h1:E4geazHk/UrJTXMlT+CBCKmn8V86RhtNeczWtfeoEFc= diff --git a/include/dhcp.go b/include/dhcp.go index 0e4b4ccf..8cf074be 100644 --- a/include/dhcp.go +++ b/include/dhcp.go @@ -2,4 +2,11 @@ package include -import _ "github.com/sagernet/sing-box/transport/dhcp" +import ( + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport/dhcp" +) + +func registerDHCPTransport(registry *dns.TransportRegistry) { + dhcp.RegisterTransport(registry) +} diff --git a/include/dhcp_stub.go b/include/dhcp_stub.go index 47a19d2e..272f313a 100644 --- a/include/dhcp_stub.go +++ b/include/dhcp_stub.go @@ -3,12 +3,18 @@ package include import ( - "github.com/sagernet/sing-dns" + "context" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" ) -func init() { - dns.RegisterTransport([]string{"dhcp"}, func(options dns.TransportOptions) (dns.Transport, error) { +func registerDHCPTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.DHCPDNSServerOptions](registry, C.DNSTypeDHCP, func(ctx context.Context, logger log.ContextLogger, tag string, options option.DHCPDNSServerOptions) (adapter.DNSTransport, error) { return nil, E.New(`DHCP is not included in this build, rebuild with -tags with_dhcp`) }) } diff --git a/include/quic.go b/include/quic.go index 980b4581..6a3f3017 100644 --- a/include/quic.go +++ b/include/quic.go @@ -5,12 +5,13 @@ package include import ( "github.com/sagernet/sing-box/adapter/inbound" "github.com/sagernet/sing-box/adapter/outbound" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport/quic" "github.com/sagernet/sing-box/protocol/hysteria" "github.com/sagernet/sing-box/protocol/hysteria2" _ "github.com/sagernet/sing-box/protocol/naive/quic" "github.com/sagernet/sing-box/protocol/tuic" _ "github.com/sagernet/sing-box/transport/v2rayquic" - _ "github.com/sagernet/sing-dns/quic" ) func registerQUICInbounds(registry *inbound.Registry) { @@ -24,3 +25,8 @@ func registerQUICOutbounds(registry *outbound.Registry) { tuic.RegisterOutbound(registry) hysteria2.RegisterOutbound(registry) } + +func registerQUICTransports(registry *dns.TransportRegistry) { + quic.RegisterTransport(registry) + quic.RegisterHTTP3Transport(registry) +} diff --git a/include/quic_stub.go b/include/quic_stub.go index 66c08590..c20a5114 100644 --- a/include/quic_stub.go +++ b/include/quic_stub.go @@ -13,20 +13,17 @@ import ( "github.com/sagernet/sing-box/common/listener" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/protocol/naive" "github.com/sagernet/sing-box/transport/v2ray" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) func init() { - dns.RegisterTransport([]string{"quic", "h3"}, func(options dns.TransportOptions) (dns.Transport, error) { - return nil, C.ErrQUICNotIncluded - }) v2ray.RegisterQUICConstructor( func(ctx context.Context, logger logger.ContextLogger, options option.V2RayQUICOptions, tlsConfig tls.ServerConfig, handler adapter.V2RayServerTransportHandler) (adapter.V2RayServerTransport, error) { return nil, C.ErrQUICNotIncluded @@ -63,3 +60,12 @@ func registerQUICOutbounds(registry *outbound.Registry) { return nil, C.ErrQUICNotIncluded }) } + +func registerQUICTransports(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.RemoteTLSDNSServerOptions](registry, C.DNSTypeQUIC, func(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteTLSDNSServerOptions) (adapter.DNSTransport, error) { + return nil, C.ErrQUICNotIncluded + }) + dns.RegisterTransport[option.RemoteHTTPSDNSServerOptions](registry, C.DNSTypeHTTP3, func(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteHTTPSDNSServerOptions) (adapter.DNSTransport, error) { + return nil, C.ErrQUICNotIncluded + }) +} diff --git a/include/registry.go b/include/registry.go index e71ffb0c..cbf793f4 100644 --- a/include/registry.go +++ b/include/registry.go @@ -8,11 +8,16 @@ import ( "github.com/sagernet/sing-box/adapter/inbound" "github.com/sagernet/sing-box/adapter/outbound" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport" + "github.com/sagernet/sing-box/dns/transport/fakeip" + "github.com/sagernet/sing-box/dns/transport/hosts" + "github.com/sagernet/sing-box/dns/transport/local" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/protocol/block" "github.com/sagernet/sing-box/protocol/direct" - "github.com/sagernet/sing-box/protocol/dns" + protocolDNS "github.com/sagernet/sing-box/protocol/dns" "github.com/sagernet/sing-box/protocol/group" "github.com/sagernet/sing-box/protocol/http" "github.com/sagernet/sing-box/protocol/mixed" @@ -61,7 +66,7 @@ func OutboundRegistry() *outbound.Registry { direct.RegisterOutbound(registry) block.RegisterOutbound(registry) - dns.RegisterOutbound(registry) + protocolDNS.RegisterOutbound(registry) group.RegisterSelector(registry) group.RegisterURLTest(registry) @@ -91,6 +96,24 @@ func EndpointRegistry() *endpoint.Registry { return registry } +func DNSTransportRegistry() *dns.TransportRegistry { + registry := dns.NewTransportRegistry() + + transport.RegisterTCP(registry) + transport.RegisterUDP(registry) + transport.RegisterTLS(registry) + transport.RegisterHTTPS(registry) + transport.RegisterPredefined(registry) + hosts.RegisterTransport(registry) + local.RegisterTransport(registry) + fakeip.RegisterTransport(registry) + + registerQUICTransports(registry) + registerDHCPTransport(registry) + + return registry +} + func registerStubForRemovedInbounds(registry *inbound.Registry) { inbound.Register[option.ShadowsocksInboundOptions](registry, C.TypeShadowsocksR, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (adapter.Inbound, error) { return nil, E.New("ShadowsocksR is deprecated and removed in sing-box 1.6.0") diff --git a/option/dns.go b/option/dns.go index 272c5180..8c9b8bda 100644 --- a/option/dns.go +++ b/option/dns.go @@ -1,29 +1,53 @@ package option import ( + "context" "net/netip" + "net/url" + "os" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/deprecated" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/json" + "github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badoption" + M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/service" + + "github.com/miekg/dns" ) -type DNSOptions struct { - Servers []DNSServerOptions `json:"servers,omitempty"` - Rules []DNSRule `json:"rules,omitempty"` - Final string `json:"final,omitempty"` - ReverseMapping bool `json:"reverse_mapping,omitempty"` - FakeIP *DNSFakeIPOptions `json:"fakeip,omitempty"` +type RawDNSOptions struct { + Servers []NewDNSServerOptions `json:"servers,omitempty"` + Rules []DNSRule `json:"rules,omitempty"` + Final string `json:"final,omitempty"` + ReverseMapping bool `json:"reverse_mapping,omitempty"` DNSClientOptions } -type DNSServerOptions struct { - Tag string `json:"tag,omitempty"` - Address string `json:"address"` - AddressResolver string `json:"address_resolver,omitempty"` - AddressStrategy DomainStrategy `json:"address_strategy,omitempty"` - AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"` - Strategy DomainStrategy `json:"strategy,omitempty"` - Detour string `json:"detour,omitempty"` - ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` +type LegacyDNSOptions struct { + FakeIP *LegacyDNSFakeIPOptions `json:"fakeip,omitempty"` +} + +type DNSOptions struct { + RawDNSOptions + LegacyDNSOptions +} + +func (o *DNSOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error { + err := json.UnmarshalContext(ctx, content, &o.LegacyDNSOptions) + if err != nil { + return err + } + if o.FakeIP != nil && o.FakeIP.Enabled { + deprecated.Report(ctx, deprecated.OptionLegacyDNSFakeIPOptions) + ctx = context.WithValue(ctx, (*LegacyDNSFakeIPOptions)(nil), o.FakeIP) + } + legacyOptions := o.LegacyDNSOptions + o.LegacyDNSOptions = LegacyDNSOptions{} + return badjson.UnmarshallExcludedContext(ctx, content, legacyOptions, &o.RawDNSOptions) } type DNSClientOptions struct { @@ -35,8 +59,261 @@ type DNSClientOptions struct { ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` } -type DNSFakeIPOptions struct { - Enabled bool `json:"enabled,omitempty"` - Inet4Range *netip.Prefix `json:"inet4_range,omitempty"` - Inet6Range *netip.Prefix `json:"inet6_range,omitempty"` +type LegacyDNSFakeIPOptions struct { + Enabled bool `json:"enabled,omitempty"` + Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"` + Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"` +} + +type DNSTransportOptionsRegistry interface { + CreateOptions(transportType string) (any, bool) +} + +type _NewDNSServerOptions struct { + Type string `json:"type,omitempty"` + Tag string `json:"tag,omitempty"` + Options any `json:"-"` +} + +type NewDNSServerOptions _NewDNSServerOptions + +func (o *NewDNSServerOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) { + return badjson.MarshallObjectsContext(ctx, (*_NewDNSServerOptions)(o), o.Options) +} + +func (o *NewDNSServerOptions) UnmarshalJSONContext(ctx context.Context, content []byte) error { + err := json.UnmarshalContext(ctx, content, (*_NewDNSServerOptions)(o)) + if err != nil { + return err + } + registry := service.FromContext[DNSTransportOptionsRegistry](ctx) + if registry == nil { + return E.New("missing outbound options registry in context") + } + var options any + switch o.Type { + case "", C.DNSTypeLegacy: + o.Type = C.DNSTypeLegacy + options = new(LegacyDNSServerOptions) + deprecated.Report(ctx, deprecated.OptionLegacyDNSTransport) + default: + var loaded bool + options, loaded = registry.CreateOptions(o.Type) + if !loaded { + return E.New("unknown transport type: ", o.Type) + } + } + err = badjson.UnmarshallExcludedContext(ctx, content, (*_Outbound)(o), options) + if err != nil { + return err + } + o.Options = options + if o.Type == C.DNSTypeLegacy { + err = o.Upgrade(ctx) + if err != nil { + return err + } + } + return nil +} + +func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error { + if o.Type != C.DNSTypeLegacy { + return nil + } + defer func() { + encoder := json.NewEncoder(os.Stderr) + encoder.SetIndent("", " ") + encoder.Encode(o) + }() + options := o.Options.(*LegacyDNSServerOptions) + serverURL, _ := url.Parse(options.Address) + var serverType string + if serverURL.Scheme != "" { + serverType = serverURL.Scheme + } else { + switch options.Address { + case "local", "fakeip": + serverType = options.Address + default: + serverType = C.DNSTypeUDP + } + } + remoteOptions := RemoteDNSServerOptions{ + LocalDNSServerOptions: LocalDNSServerOptions{ + DialerOptions: DialerOptions{ + Detour: options.Detour, + }, + LegacyStrategy: options.Strategy, + LegacyDefaultDialer: options.Detour == "", + LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}), + }, + AddressResolver: options.AddressResolver, + AddressStrategy: options.AddressStrategy, + AddressFallbackDelay: options.AddressFallbackDelay, + } + switch serverType { + case C.DNSTypeLocal: + o.Type = C.DNSTypeLocal + o.Options = &remoteOptions.LocalDNSServerOptions + case C.DNSTypeUDP: + o.Type = C.DNSTypeUDP + o.Options = &remoteOptions + var serverAddr M.Socksaddr + if serverURL.Scheme == "" { + serverAddr = M.ParseSocksaddr(options.Address) + } else { + serverAddr = M.ParseSocksaddr(serverURL.Host) + } + if !serverAddr.IsValid() { + return E.New("invalid server address") + } + remoteOptions.Server = serverAddr.Addr.String() + if serverAddr.Port != 0 && serverAddr.Port != 53 { + remoteOptions.ServerPort = serverAddr.Port + } + remoteOptions.Server = serverAddr.AddrString() + remoteOptions.ServerPort = serverAddr.Port + case C.DNSTypeTCP: + o.Type = C.DNSTypeTCP + o.Options = &remoteOptions + serverAddr := M.ParseSocksaddr(serverURL.Host) + if !serverAddr.IsValid() { + return E.New("invalid server address") + } + remoteOptions.Server = serverAddr.Addr.String() + if serverAddr.Port != 0 && serverAddr.Port != 53 { + remoteOptions.ServerPort = serverAddr.Port + } + remoteOptions.Server = serverAddr.AddrString() + remoteOptions.ServerPort = serverAddr.Port + case C.DNSTypeTLS, C.DNSTypeQUIC: + o.Type = serverType + serverAddr := M.ParseSocksaddr(serverURL.Host) + if !serverAddr.IsValid() { + return E.New("invalid server address") + } + remoteOptions.Server = serverAddr.Addr.String() + if serverAddr.Port != 0 && serverAddr.Port != 853 { + remoteOptions.ServerPort = serverAddr.Port + } + o.Options = &RemoteTLSDNSServerOptions{ + RemoteDNSServerOptions: remoteOptions, + } + case C.DNSTypeHTTPS, C.DNSTypeHTTP3: + o.Type = serverType + httpsOptions := RemoteHTTPSDNSServerOptions{ + RemoteTLSDNSServerOptions: RemoteTLSDNSServerOptions{ + RemoteDNSServerOptions: remoteOptions, + }, + } + o.Options = &httpsOptions + serverAddr := M.ParseSocksaddr(serverURL.Host) + if !serverAddr.IsValid() { + return E.New("invalid server address") + } + httpsOptions.Server = serverAddr.Addr.String() + if serverAddr.Port != 0 && serverAddr.Port != 443 { + httpsOptions.ServerPort = serverAddr.Port + } + if serverURL.Path != "/dns-query" { + httpsOptions.Path = serverURL.Path + } + case "rcode": + var rcode int + switch serverURL.Host { + case "success": + rcode = dns.RcodeSuccess + case "format_error": + rcode = dns.RcodeFormatError + case "server_failure": + rcode = dns.RcodeServerFailure + case "name_error": + rcode = dns.RcodeNameError + case "not_implemented": + rcode = dns.RcodeNotImplemented + case "refused": + rcode = dns.RcodeRefused + default: + return E.New("unknown rcode: ", serverURL.Host) + } + o.Type = C.DNSTypePreDefined + o.Options = &PredefinedDNSServerOptions{ + Responses: []DNSResponseOptions{ + { + RCode: common.Ptr(DNSRCode(rcode)), + }, + }, + } + case C.DNSTypeDHCP: + o.Type = C.DNSTypeDHCP + dhcpOptions := DHCPDNSServerOptions{} + if serverURL.Host != "" && serverURL.Host != "auto" { + dhcpOptions.Interface = serverURL.Host + } + o.Options = &dhcpOptions + case C.DNSTypeFakeIP: + o.Type = C.DNSTypeFakeIP + fakeipOptions := FakeIPDNSServerOptions{} + if legacyOptions, loaded := ctx.Value((*LegacyDNSFakeIPOptions)(nil)).(*LegacyDNSFakeIPOptions); loaded { + fakeipOptions.Inet4Range = legacyOptions.Inet4Range + fakeipOptions.Inet6Range = legacyOptions.Inet6Range + } + o.Options = &fakeipOptions + default: + return E.New("unsupported DNS server scheme: ", serverType) + } + return nil +} + +type LegacyDNSServerOptions struct { + Address string `json:"address"` + AddressResolver string `json:"address_resolver,omitempty"` + AddressStrategy DomainStrategy `json:"address_strategy,omitempty"` + AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"` + Strategy DomainStrategy `json:"strategy,omitempty"` + Detour string `json:"detour,omitempty"` + ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` +} + +type HostsDNSServerOptions struct { + Path badoption.Listable[string] `json:"path,omitempty"` + Predefined badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"` +} + +type LocalDNSServerOptions struct { + DialerOptions + LegacyStrategy DomainStrategy `json:"-"` + LegacyDefaultDialer bool `json:"-"` + LegacyClientSubnet netip.Prefix `json:"-"` +} + +type RemoteDNSServerOptions struct { + LocalDNSServerOptions + ServerOptions + AddressResolver string `json:"address_resolver,omitempty"` + AddressStrategy DomainStrategy `json:"address_strategy,omitempty"` + AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"` +} + +type RemoteTLSDNSServerOptions struct { + RemoteDNSServerOptions + OutboundTLSOptionsContainer +} + +type RemoteHTTPSDNSServerOptions struct { + RemoteTLSDNSServerOptions + Path string `json:"path,omitempty"` + Method string `json:"method,omitempty"` + Headers badoption.HTTPHeader `json:"headers,omitempty"` +} + +type FakeIPDNSServerOptions struct { + Inet4Range *badoption.Prefix `json:"inet4_range,omitempty"` + Inet6Range *badoption.Prefix `json:"inet6_range,omitempty"` +} + +type DHCPDNSServerOptions struct { + LocalDNSServerOptions + Interface string `json:"interface,omitempty"` } diff --git a/option/dns_record.go b/option/dns_record.go new file mode 100644 index 00000000..c76a76c6 --- /dev/null +++ b/option/dns_record.go @@ -0,0 +1,161 @@ +package option + +import ( + "encoding/base64" + + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/json" + "github.com/sagernet/sing/common/json/badoption" + M "github.com/sagernet/sing/common/metadata" + + "github.com/miekg/dns" +) + +type PredefinedDNSServerOptions struct { + Responses []DNSResponseOptions `json:"responses,omitempty"` +} + +type DNSResponseOptions struct { + Query badoption.Listable[string] `json:"query,omitempty"` + QueryType badoption.Listable[DNSQueryType] `json:"query_type,omitempty"` + + RCode *DNSRCode `json:"rcode,omitempty"` + Answer badoption.Listable[DNSRecordOptions] `json:"answer,omitempty"` + Ns badoption.Listable[DNSRecordOptions] `json:"ns,omitempty"` + Extra badoption.Listable[DNSRecordOptions] `json:"extra,omitempty"` +} + +type DNSRCode int + +func (r DNSRCode) MarshalJSON() ([]byte, error) { + rCodeValue, loaded := dns.RcodeToString[int(r)] + if loaded { + return json.Marshal(rCodeValue) + } + return json.Marshal(int(r)) +} + +func (r *DNSRCode) UnmarshalJSON(bytes []byte) error { + var intValue int + err := json.Unmarshal(bytes, &intValue) + if err == nil { + *r = DNSRCode(intValue) + return nil + } + var stringValue string + err = json.Unmarshal(bytes, &stringValue) + if err != nil { + return err + } + rCodeValue, loaded := dns.StringToRcode[stringValue] + if !loaded { + return E.New("unknown rcode: " + stringValue) + } + *r = DNSRCode(rCodeValue) + return nil +} + +func (r *DNSRCode) Build() int { + if r == nil { + return dns.RcodeSuccess + } + return int(*r) +} + +func (o DNSResponseOptions) Build() ([]dns.Question, *dns.Msg, error) { + var questions []dns.Question + if len(o.Query) == 0 && len(o.QueryType) == 0 { + questions = []dns.Question{{Qclass: dns.ClassINET}} + } else if len(o.Query) == 0 { + for _, queryType := range o.QueryType { + questions = append(questions, dns.Question{ + Qtype: uint16(queryType), + Qclass: dns.ClassINET, + }) + } + } else if len(o.QueryType) == 0 { + for _, domain := range o.Query { + questions = append(questions, dns.Question{ + Name: dns.Fqdn(domain), + Qclass: dns.ClassINET, + }) + } + } else { + for _, queryType := range o.QueryType { + for _, domain := range o.Query { + questions = append(questions, dns.Question{ + Name: dns.Fqdn(domain), + Qtype: uint16(queryType), + Qclass: dns.ClassINET, + }) + } + } + } + return questions, &dns.Msg{ + MsgHdr: dns.MsgHdr{ + Response: true, + Rcode: o.RCode.Build(), + Authoritative: true, + RecursionDesired: true, + RecursionAvailable: true, + }, + Answer: common.Map(o.Answer, DNSRecordOptions.build), + Ns: common.Map(o.Ns, DNSRecordOptions.build), + Extra: common.Map(o.Extra, DNSRecordOptions.build), + }, nil +} + +type DNSRecordOptions struct { + dns.RR + fromBase64 bool +} + +func (o DNSRecordOptions) MarshalJSON() ([]byte, error) { + if o.fromBase64 { + buffer := buf.Get(dns.Len(o.RR)) + defer buf.Put(buffer) + offset, err := dns.PackRR(o.RR, buffer, 0, nil, false) + if err != nil { + return nil, err + } + return json.Marshal(base64.StdEncoding.EncodeToString(buffer[:offset])) + } + return json.Marshal(o.RR.String()) +} + +func (o *DNSRecordOptions) UnmarshalJSON(data []byte) error { + var stringValue string + err := json.Unmarshal(data, &stringValue) + if err != nil { + return err + } + binary, err := base64.StdEncoding.DecodeString(stringValue) + if err == nil { + return o.unmarshalBase64(binary) + } + record, err := dns.NewRR(stringValue) + if err != nil { + return err + } + if a, isA := record.(*dns.A); isA { + a.A = M.AddrFromIP(a.A).Unmap().AsSlice() + } + o.RR = record + return nil +} + +func (o *DNSRecordOptions) unmarshalBase64(binary []byte) error { + record, _, err := dns.UnpackRR(binary, 0) + if err != nil { + return E.New("parse binary DNS record") + } + o.RR = record + o.fromBase64 = true + return nil +} + +func (o DNSRecordOptions) build() dns.RR { + return o.RR +} diff --git a/option/rule_action.go b/option/rule_action.go index b7003628..a715d260 100644 --- a/option/rule_action.go +++ b/option/rule_action.go @@ -7,7 +7,6 @@ import ( "time" C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-dns" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json/badjson" @@ -168,12 +167,14 @@ func (r *RouteOptionsActionOptions) UnmarshalJSON(data []byte) error { type DNSRouteActionOptions struct { Server string `json:"server,omitempty"` + Strategy DomainStrategy `json:"strategy,omitempty"` DisableCache bool `json:"disable_cache,omitempty"` RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"` ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` } type _DNSRouteOptionsActionOptions struct { + Strategy DomainStrategy `json:"strategy,omitempty"` DisableCache bool `json:"disable_cache,omitempty"` RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"` ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` @@ -225,7 +226,7 @@ func (d DirectActionOptions) Descriptions() []string { if d.UDPFragment != nil { descriptions = append(descriptions, "udp_fragment="+fmt.Sprint(*d.UDPFragment)) } - if d.DomainStrategy != DomainStrategy(dns.DomainStrategyAsIS) { + if d.DomainStrategy != DomainStrategy(C.DomainStrategyAsIS) { descriptions = append(descriptions, "domain_strategy="+d.DomainStrategy.String()) } if d.FallbackDelay != 0 { @@ -252,6 +253,14 @@ type _RejectActionOptions struct { type RejectActionOptions _RejectActionOptions +func (r RejectActionOptions) MarshalJSON() ([]byte, error) { + switch r.Method { + case C.RuleActionRejectMethodDefault: + r.Method = "" + } + return json.Marshal((_RejectActionOptions)(r)) +} + func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error { err := json.Unmarshal(bytes, (*_RejectActionOptions)(r)) if err != nil { diff --git a/option/rule_dns.go b/option/rule_dns.go index b437eb54..9d6fb138 100644 --- a/option/rule_dns.go +++ b/option/rule_dns.go @@ -83,6 +83,7 @@ type RawDefaultDNSRule struct { GeoIP badoption.Listable[string] `json:"geoip,omitempty"` IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty"` IPIsPrivate bool `json:"ip_is_private,omitempty"` + IPAcceptAny bool `json:"ip_accept_any,omitempty"` SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty"` SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"` SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"` diff --git a/option/types.go b/option/types.go index 66f58ef8..fe7d4b3d 100644 --- a/option/types.go +++ b/option/types.go @@ -4,7 +4,6 @@ import ( "strings" C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-dns" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/json" @@ -45,19 +44,19 @@ func (v NetworkList) Build() []string { return strings.Split(string(v), "\n") } -type DomainStrategy dns.DomainStrategy +type DomainStrategy C.DomainStrategy func (s DomainStrategy) String() string { - switch dns.DomainStrategy(s) { - case dns.DomainStrategyAsIS: + switch C.DomainStrategy(s) { + case C.DomainStrategyAsIS: return "" - case dns.DomainStrategyPreferIPv4: + case C.DomainStrategyPreferIPv4: return "prefer_ipv4" - case dns.DomainStrategyPreferIPv6: + case C.DomainStrategyPreferIPv6: return "prefer_ipv6" - case dns.DomainStrategyUseIPv4: + case C.DomainStrategyIPv4Only: return "ipv4_only" - case dns.DomainStrategyUseIPv6: + case C.DomainStrategyIPv6Only: return "ipv6_only" default: panic(E.New("unknown domain strategy: ", s)) @@ -66,17 +65,17 @@ func (s DomainStrategy) String() string { func (s DomainStrategy) MarshalJSON() ([]byte, error) { var value string - switch dns.DomainStrategy(s) { - case dns.DomainStrategyAsIS: + switch C.DomainStrategy(s) { + case C.DomainStrategyAsIS: value = "" // value = "as_is" - case dns.DomainStrategyPreferIPv4: + case C.DomainStrategyPreferIPv4: value = "prefer_ipv4" - case dns.DomainStrategyPreferIPv6: + case C.DomainStrategyPreferIPv6: value = "prefer_ipv6" - case dns.DomainStrategyUseIPv4: + case C.DomainStrategyIPv4Only: value = "ipv4_only" - case dns.DomainStrategyUseIPv6: + case C.DomainStrategyIPv6Only: value = "ipv6_only" default: return nil, E.New("unknown domain strategy: ", s) @@ -92,15 +91,15 @@ func (s *DomainStrategy) UnmarshalJSON(bytes []byte) error { } switch value { case "", "as_is": - *s = DomainStrategy(dns.DomainStrategyAsIS) + *s = DomainStrategy(C.DomainStrategyAsIS) case "prefer_ipv4": - *s = DomainStrategy(dns.DomainStrategyPreferIPv4) + *s = DomainStrategy(C.DomainStrategyPreferIPv4) case "prefer_ipv6": - *s = DomainStrategy(dns.DomainStrategyPreferIPv6) + *s = DomainStrategy(C.DomainStrategyPreferIPv6) case "ipv4_only": - *s = DomainStrategy(dns.DomainStrategyUseIPv4) + *s = DomainStrategy(C.DomainStrategyIPv4Only) case "ipv6_only": - *s = DomainStrategy(dns.DomainStrategyUseIPv6) + *s = DomainStrategy(C.DomainStrategyIPv6Only) default: return E.New("unknown domain strategy: ", value) } diff --git a/protocol/direct/outbound.go b/protocol/direct/outbound.go index aba56336..d173ec53 100644 --- a/protocol/direct/outbound.go +++ b/protocol/direct/outbound.go @@ -12,7 +12,6 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" @@ -34,7 +33,7 @@ type Outbound struct { outbound.Adapter logger logger.ContextLogger dialer dialer.ParallelInterfaceDialer - domainStrategy dns.DomainStrategy + domainStrategy C.DomainStrategy fallbackDelay time.Duration overrideOption int overrideDestination M.Socksaddr @@ -50,7 +49,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL outbound := &Outbound{ Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), logger: logger, - domainStrategy: dns.DomainStrategy(options.DomainStrategy), + domainStrategy: C.DomainStrategy(options.DomainStrategy), fallbackDelay: time.Duration(options.FallbackDelay), dialer: outboundDialer, // loopBack: newLoopBackDetector(router), @@ -151,26 +150,26 @@ func (h *Outbound) DialParallel(ctx context.Context, network string, destination case N.NetworkUDP: h.logger.InfoContext(ctx, "outbound packet connection to ", destination) } - var domainStrategy dns.DomainStrategy - if h.domainStrategy != dns.DomainStrategyAsIS { + var domainStrategy C.DomainStrategy + if h.domainStrategy != C.DomainStrategyAsIS { domainStrategy = h.domainStrategy } else { //nolint:staticcheck - domainStrategy = dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) + domainStrategy = C.DomainStrategy(metadata.InboundOptions.DomainStrategy) } switch domainStrategy { - case dns.DomainStrategyUseIPv4: + case C.DomainStrategyIPv4Only: destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is4) if len(destinationAddresses) == 0 { return nil, E.New("no IPv4 address available for ", destination) } - case dns.DomainStrategyUseIPv6: + case C.DomainStrategyIPv6Only: destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is6) if len(destinationAddresses) == 0 { return nil, E.New("no IPv6 address available for ", destination) } } - return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, nil, nil, nil, h.fallbackDelay) + return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == C.DomainStrategyPreferIPv6, nil, nil, nil, h.fallbackDelay) } func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { @@ -191,26 +190,26 @@ func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, dest case N.NetworkUDP: h.logger.InfoContext(ctx, "outbound packet connection to ", destination) } - var domainStrategy dns.DomainStrategy - if h.domainStrategy != dns.DomainStrategyAsIS { + var domainStrategy C.DomainStrategy + if h.domainStrategy != C.DomainStrategyAsIS { domainStrategy = h.domainStrategy } else { //nolint:staticcheck - domainStrategy = dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) + domainStrategy = C.DomainStrategy(metadata.InboundOptions.DomainStrategy) } switch domainStrategy { - case dns.DomainStrategyUseIPv4: + case C.DomainStrategyIPv4Only: destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is4) if len(destinationAddresses) == 0 { return nil, E.New("no IPv4 address available for ", destination) } - case dns.DomainStrategyUseIPv6: + case C.DomainStrategyIPv6Only: destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is6) if len(destinationAddresses) == 0 { return nil, E.New("no IPv6 address available for ", destination) } } - return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, networkStrategy, networkType, fallbackNetworkType, fallbackDelay) + return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == C.DomainStrategyPreferIPv6, networkStrategy, networkType, fallbackNetworkType, fallbackDelay) } func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) { diff --git a/protocol/dns/handle.go b/protocol/dns/handle.go index bc58d9e2..c4ad79d9 100644 --- a/protocol/dns/handle.go +++ b/protocol/dns/handle.go @@ -7,7 +7,7 @@ import ( "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-dns" + "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" @@ -19,7 +19,7 @@ import ( mDNS "github.com/miekg/dns" ) -func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net.Conn, metadata adapter.InboundContext) error { +func HandleStreamDNSRequest(ctx context.Context, router adapter.DNSRouter, conn net.Conn, metadata adapter.InboundContext) error { var queryLength uint16 err := binary.Read(conn, binary.BigEndian, &queryLength) if err != nil { @@ -41,7 +41,7 @@ func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net } metadataInQuery := metadata go func() error { - response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message) + response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message, adapter.DNSQueryOptions{}) if err != nil { conn.Close() return err @@ -61,7 +61,7 @@ func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net return nil } -func NewDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.PacketConn, cachedPackets []*N.PacketBuffer, metadata adapter.InboundContext) error { +func NewDNSPacketConnection(ctx context.Context, router adapter.DNSRouter, conn N.PacketConn, cachedPackets []*N.PacketBuffer, metadata adapter.InboundContext) error { metadata.Destination = M.Socksaddr{} var reader N.PacketReader = conn var counters []N.CountFunc @@ -123,7 +123,7 @@ func NewDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.P } metadataInQuery := metadata go func() error { - response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message) + response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message, adapter.DNSQueryOptions{}) if err != nil { cancel(err) return err @@ -148,7 +148,7 @@ func NewDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.P return group.Run(fastClose) } -func newDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error { +func newDNSPacketConnection(ctx context.Context, router adapter.DNSRouter, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error { fastClose, cancel := common.ContextWithCancelCause(ctx) timeout := canceler.New(fastClose, cancel, C.DNSTimeout) var group task.Group @@ -193,7 +193,7 @@ func newDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.P } metadataInQuery := metadata go func() error { - response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message) + response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message, adapter.DNSQueryOptions{}) if err != nil { cancel(err) return err diff --git a/protocol/dns/outbound.go b/protocol/dns/outbound.go index 5f06557b..277d7454 100644 --- a/protocol/dns/outbound.go +++ b/protocol/dns/outbound.go @@ -14,6 +14,7 @@ import ( "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" ) func RegisterOutbound(registry *outbound.Registry) { @@ -22,14 +23,14 @@ func RegisterOutbound(registry *outbound.Registry) { type Outbound struct { outbound.Adapter - router adapter.Router + router adapter.DNSRouter logger logger.ContextLogger } func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.StubOptions) (adapter.Outbound, error) { return &Outbound{ Adapter: outbound.NewAdapter(C.TypeDNS, tag, []string{N.NetworkTCP, N.NetworkUDP}, nil), - router: router, + router: service.FromContext[adapter.DNSRouter](ctx), logger: logger, }, nil } diff --git a/protocol/socks/outbound.go b/protocol/socks/outbound.go index 0632f082..323149e2 100644 --- a/protocol/socks/outbound.go +++ b/protocol/socks/outbound.go @@ -17,6 +17,7 @@ import ( N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/uot" "github.com/sagernet/sing/protocol/socks" + "github.com/sagernet/sing/service" ) func RegisterOutbound(registry *outbound.Registry) { @@ -27,7 +28,7 @@ var _ adapter.Outbound = (*Outbound)(nil) type Outbound struct { outbound.Adapter - router adapter.Router + dnsRouter adapter.DNSRouter logger logger.ContextLogger client *socks.Client resolve bool @@ -50,11 +51,11 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL return nil, err } outbound := &Outbound{ - Adapter: outbound.NewAdapterWithDialerOptions(C.TypeSOCKS, tag, options.Network.Build(), options.DialerOptions), - router: router, - logger: logger, - client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password), - resolve: version == socks.Version4, + Adapter: outbound.NewAdapterWithDialerOptions(C.TypeSOCKS, tag, options.Network.Build(), options.DialerOptions), + dnsRouter: service.FromContext[adapter.DNSRouter](ctx), + logger: logger, + client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password), + resolve: version == socks.Version4, } uotOptions := common.PtrValueOrDefault(options.UDPOverTCP) if uotOptions.Enabled { @@ -83,7 +84,7 @@ func (h *Outbound) DialContext(ctx context.Context, network string, destination return nil, E.Extend(N.ErrUnknownNetwork, network) } if h.resolve && destination.IsFqdn() { - destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn) + destinationAddresses, err := h.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) if err != nil { return nil, err } @@ -101,7 +102,7 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n return h.uotClient.ListenPacket(ctx, destination) } if h.resolve && destination.IsFqdn() { - destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn) + destinationAddresses, err := h.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) if err != nil { return nil, err } diff --git a/protocol/wireguard/endpoint.go b/protocol/wireguard/endpoint.go index 21d72bd9..300701a9 100644 --- a/protocol/wireguard/endpoint.go +++ b/protocol/wireguard/endpoint.go @@ -13,13 +13,13 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/wireguard" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" ) func RegisterEndpoint(registry *endpoint.Registry) { @@ -35,6 +35,7 @@ type Endpoint struct { endpoint.Adapter ctx context.Context router adapter.Router + dnsRouter adapter.DNSRouter logger logger.ContextLogger localAddresses []netip.Prefix endpoint *wireguard.Endpoint @@ -45,6 +46,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), ctx: ctx, router: router, + dnsRouter: service.FromContext[adapter.DNSRouter](ctx), logger: logger, localAddresses: options.Address, } @@ -79,7 +81,9 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL PrivateKey: options.PrivateKey, ListenPort: options.ListenPort, ResolvePeer: func(domain string) (netip.Addr, error) { - endpointAddresses, lookupErr := router.Lookup(ctx, domain, dns.DomainStrategy(options.DomainStrategy)) + endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{ + Strategy: C.DomainStrategy(options.DomainStrategy), + }) if lookupErr != nil { return netip.Addr{}, lookupErr } @@ -185,7 +189,7 @@ func (w *Endpoint) DialContext(ctx context.Context, network string, destination w.logger.InfoContext(ctx, "outbound packet connection to ", destination) } if destination.IsFqdn() { - destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn) + destinationAddresses, err := w.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) if err != nil { return nil, err } @@ -199,7 +203,7 @@ func (w *Endpoint) DialContext(ctx context.Context, network string, destination func (w *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { w.logger.InfoContext(ctx, "outbound packet connection to ", destination) if destination.IsFqdn() { - destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn) + destinationAddresses, err := w.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) if err != nil { return nil, err } diff --git a/protocol/wireguard/outbound.go b/protocol/wireguard/outbound.go index 3e299705..4aa49a8d 100644 --- a/protocol/wireguard/outbound.go +++ b/protocol/wireguard/outbound.go @@ -13,12 +13,12 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/wireguard" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" ) func RegisterOutbound(registry *outbound.Registry) { @@ -33,7 +33,7 @@ var ( type Outbound struct { outbound.Adapter ctx context.Context - router adapter.Router + dnsRouter adapter.DNSRouter logger logger.ContextLogger localAddresses []netip.Prefix endpoint *wireguard.Endpoint @@ -47,7 +47,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL outbound := &Outbound{ Adapter: outbound.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), ctx: ctx, - router: router, + dnsRouter: service.FromContext[adapter.DNSRouter](ctx), logger: logger, localAddresses: options.LocalAddress, } @@ -94,7 +94,9 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL Address: options.LocalAddress, PrivateKey: options.PrivateKey, ResolvePeer: func(domain string) (netip.Addr, error) { - endpointAddresses, lookupErr := router.Lookup(ctx, domain, dns.DomainStrategy(options.DomainStrategy)) + endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{ + Strategy: C.DomainStrategy(options.DomainStrategy), + }) if lookupErr != nil { return netip.Addr{}, lookupErr } @@ -137,7 +139,7 @@ func (o *Outbound) DialContext(ctx context.Context, network string, destination o.logger.InfoContext(ctx, "outbound packet connection to ", destination) } if destination.IsFqdn() { - destinationAddresses, err := o.router.LookupDefault(ctx, destination.Fqdn) + destinationAddresses, err := o.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) if err != nil { return nil, err } @@ -151,7 +153,7 @@ func (o *Outbound) DialContext(ctx context.Context, network string, destination func (o *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { o.logger.InfoContext(ctx, "outbound packet connection to ", destination) if destination.IsFqdn() { - destinationAddresses, err := o.router.LookupDefault(ctx, destination.Fqdn) + destinationAddresses, err := o.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) if err != nil { return nil, err } diff --git a/release/config/config.json b/release/config/config.json index c518d18b..bdc78d40 100644 --- a/release/config/config.json +++ b/release/config/config.json @@ -14,10 +14,13 @@ "type": "shadowsocks", "listen": "::", "listen_port": 8080, - "sniff": true, "network": "tcp", "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" + "password": "Gn1JUS14bLUHgv1cWDDp4A==", + "multiplex": { + "enabled": true, + "padding": true + } } ], "outbounds": [ @@ -32,7 +35,7 @@ "route": { "rules": [ { - "protocol": "dns", + "port": 53, "outbound": "dns-out" } ] diff --git a/route/dns.go b/route/dns.go index 2c6efefe..7d2b5778 100644 --- a/route/dns.go +++ b/route/dns.go @@ -8,11 +8,12 @@ import ( "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" dnsOutbound "github.com/sagernet/sing-box/protocol/dns" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/udpnat2" @@ -24,7 +25,7 @@ func (r *Router) hijackDNSStream(ctx context.Context, conn net.Conn, metadata ad metadata.Destination = M.Socksaddr{} for { conn.SetReadDeadline(time.Now().Add(C.DNSTimeout)) - err := dnsOutbound.HandleStreamDNSRequest(ctx, r, conn, metadata) + err := dnsOutbound.HandleStreamDNSRequest(ctx, r.dns, conn, metadata) if err != nil { return err } @@ -38,37 +39,38 @@ func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetB buffer := packet.Buffer destination := packet.Destination N.PutPacketBuffer(packet) - go ExchangeDNSPacket(ctx, r, natConn, buffer, metadata, destination) + go ExchangeDNSPacket(ctx, r.dns, r.logger, natConn, buffer, metadata, destination) } natConn.SetHandler(&dnsHijacker{ - router: r, + router: r.dns, + logger: r.logger, conn: conn, ctx: ctx, metadata: metadata, }) return } - err := dnsOutbound.NewDNSPacketConnection(ctx, r, conn, packetBuffers, metadata) + err := dnsOutbound.NewDNSPacketConnection(ctx, r.dns, conn, packetBuffers, metadata) if err != nil && !E.IsClosedOrCanceled(err) { - r.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection")) + r.logger.ErrorContext(ctx, E.Cause(err, "process DNS packet connection")) } } -func ExchangeDNSPacket(ctx context.Context, router *Router, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) { +func ExchangeDNSPacket(ctx context.Context, router adapter.DNSRouter, logger logger.ContextLogger, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) { err := exchangeDNSPacket(ctx, router, conn, buffer, metadata, destination) if err != nil && !errors.Is(err, tun.ErrDrop) && !E.IsClosedOrCanceled(err) { - router.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection")) + logger.ErrorContext(ctx, E.Cause(err, "process DNS packet connection")) } } -func exchangeDNSPacket(ctx context.Context, router *Router, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) error { +func exchangeDNSPacket(ctx context.Context, router adapter.DNSRouter, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) error { var message mDNS.Msg err := message.Unpack(buffer.Bytes()) buffer.Release() if err != nil { return E.Cause(err, "unpack request") } - response, err := router.Exchange(adapter.WithContext(ctx, &metadata), &message) + response, err := router.Exchange(adapter.WithContext(ctx, &metadata), &message, adapter.DNSQueryOptions{}) if err != nil { return err } @@ -81,12 +83,13 @@ func exchangeDNSPacket(ctx context.Context, router *Router, conn N.PacketConn, b } type dnsHijacker struct { - router *Router + router adapter.DNSRouter + logger logger.ContextLogger conn N.PacketConn ctx context.Context metadata adapter.InboundContext } func (h *dnsHijacker) NewPacketEx(buffer *buf.Buffer, destination M.Socksaddr) { - go ExchangeDNSPacket(h.ctx, h.router, h.conn, buffer, h.metadata, destination) + go ExchangeDNSPacket(h.ctx, h.router, h.logger, h.conn, buffer, h.metadata, destination) } diff --git a/route/geo_resources.go b/route/geo_resources.go deleted file mode 100644 index 8a8a3ef5..00000000 --- a/route/geo_resources.go +++ /dev/null @@ -1,246 +0,0 @@ -package route - -import ( - "context" - "io" - "net" - "net/http" - "os" - "path/filepath" - - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/geoip" - "github.com/sagernet/sing-box/common/geosite" - C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-box/experimental/deprecated" - R "github.com/sagernet/sing-box/route/rule" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - "github.com/sagernet/sing/common/rw" - "github.com/sagernet/sing/service/filemanager" -) - -func (r *Router) GeoIPReader() *geoip.Reader { - return r.geoIPReader -} - -func (r *Router) LoadGeosite(code string) (adapter.Rule, error) { - rule, cached := r.geositeCache[code] - if cached { - return rule, nil - } - items, err := r.geositeReader.Read(code) - if err != nil { - return nil, err - } - rule, err = R.NewDefaultRule(r.ctx, nil, geosite.Compile(items)) - if err != nil { - return nil, err - } - r.geositeCache[code] = rule - return rule, nil -} - -func (r *Router) prepareGeoIPDatabase() error { - deprecated.Report(r.ctx, deprecated.OptionGEOIP) - var geoPath string - if r.geoIPOptions.Path != "" { - geoPath = r.geoIPOptions.Path - } else { - geoPath = "geoip.db" - if foundPath, loaded := C.FindPath(geoPath); loaded { - geoPath = foundPath - } - } - if !rw.IsFile(geoPath) { - geoPath = filemanager.BasePath(r.ctx, geoPath) - } - if stat, err := os.Stat(geoPath); err == nil { - if stat.IsDir() { - return E.New("geoip path is a directory: ", geoPath) - } - if stat.Size() == 0 { - os.Remove(geoPath) - } - } - if !rw.IsFile(geoPath) { - r.logger.Warn("geoip database not exists: ", geoPath) - var err error - for attempts := 0; attempts < 3; attempts++ { - err = r.downloadGeoIPDatabase(geoPath) - if err == nil { - break - } - r.logger.Error("download geoip database: ", err) - os.Remove(geoPath) - // time.Sleep(10 * time.Second) - } - if err != nil { - return err - } - } - geoReader, codes, err := geoip.Open(geoPath) - if err != nil { - return E.Cause(err, "open geoip database") - } - r.logger.Info("loaded geoip database: ", len(codes), " codes") - r.geoIPReader = geoReader - return nil -} - -func (r *Router) prepareGeositeDatabase() error { - deprecated.Report(r.ctx, deprecated.OptionGEOSITE) - var geoPath string - if r.geositeOptions.Path != "" { - geoPath = r.geositeOptions.Path - } else { - geoPath = "geosite.db" - if foundPath, loaded := C.FindPath(geoPath); loaded { - geoPath = foundPath - } - } - if !rw.IsFile(geoPath) { - geoPath = filemanager.BasePath(r.ctx, geoPath) - } - if stat, err := os.Stat(geoPath); err == nil { - if stat.IsDir() { - return E.New("geoip path is a directory: ", geoPath) - } - if stat.Size() == 0 { - os.Remove(geoPath) - } - } - if !rw.IsFile(geoPath) { - r.logger.Warn("geosite database not exists: ", geoPath) - var err error - for attempts := 0; attempts < 3; attempts++ { - err = r.downloadGeositeDatabase(geoPath) - if err == nil { - break - } - r.logger.Error("download geosite database: ", err) - os.Remove(geoPath) - } - if err != nil { - return err - } - } - geoReader, codes, err := geosite.Open(geoPath) - if err == nil { - r.logger.Info("loaded geosite database: ", len(codes), " codes") - r.geositeReader = geoReader - } else { - return E.Cause(err, "open geosite database") - } - return nil -} - -func (r *Router) downloadGeoIPDatabase(savePath string) error { - var downloadURL string - if r.geoIPOptions.DownloadURL != "" { - downloadURL = r.geoIPOptions.DownloadURL - } else { - downloadURL = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db" - } - r.logger.Info("downloading geoip database") - var detour adapter.Outbound - if r.geoIPOptions.DownloadDetour != "" { - outbound, loaded := r.outbound.Outbound(r.geoIPOptions.DownloadDetour) - if !loaded { - return E.New("detour outbound not found: ", r.geoIPOptions.DownloadDetour) - } - detour = outbound - } else { - detour = r.outbound.Default() - } - - if parentDir := filepath.Dir(savePath); parentDir != "" { - filemanager.MkdirAll(r.ctx, parentDir, 0o755) - } - - httpClient := &http.Client{ - Transport: &http.Transport{ - ForceAttemptHTTP2: true, - TLSHandshakeTimeout: C.TCPTimeout, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return detour.DialContext(ctx, network, M.ParseSocksaddr(addr)) - }, - }, - } - defer httpClient.CloseIdleConnections() - request, err := http.NewRequest("GET", downloadURL, nil) - if err != nil { - return err - } - response, err := httpClient.Do(request.WithContext(r.ctx)) - if err != nil { - return err - } - defer response.Body.Close() - - saveFile, err := filemanager.Create(r.ctx, savePath) - if err != nil { - return E.Cause(err, "open output file: ", downloadURL) - } - _, err = io.Copy(saveFile, response.Body) - saveFile.Close() - if err != nil { - filemanager.Remove(r.ctx, savePath) - } - return err -} - -func (r *Router) downloadGeositeDatabase(savePath string) error { - var downloadURL string - if r.geositeOptions.DownloadURL != "" { - downloadURL = r.geositeOptions.DownloadURL - } else { - downloadURL = "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db" - } - r.logger.Info("downloading geosite database") - var detour adapter.Outbound - if r.geositeOptions.DownloadDetour != "" { - outbound, loaded := r.outbound.Outbound(r.geositeOptions.DownloadDetour) - if !loaded { - return E.New("detour outbound not found: ", r.geositeOptions.DownloadDetour) - } - detour = outbound - } else { - detour = r.outbound.Default() - } - - if parentDir := filepath.Dir(savePath); parentDir != "" { - filemanager.MkdirAll(r.ctx, parentDir, 0o755) - } - - httpClient := &http.Client{ - Transport: &http.Transport{ - ForceAttemptHTTP2: true, - TLSHandshakeTimeout: C.TCPTimeout, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return detour.DialContext(ctx, network, M.ParseSocksaddr(addr)) - }, - }, - } - defer httpClient.CloseIdleConnections() - request, err := http.NewRequest("GET", downloadURL, nil) - if err != nil { - return err - } - response, err := httpClient.Do(request.WithContext(r.ctx)) - if err != nil { - return err - } - defer response.Body.Close() - - saveFile, err := filemanager.Create(r.ctx, savePath) - if err != nil { - return E.Cause(err, "open output file: ", downloadURL) - } - _, err = io.Copy(saveFile, response.Body) - saveFile.Close() - if err != nil { - filemanager.Remove(r.ctx, savePath) - } - return err -} diff --git a/route/route.go b/route/route.go index bb484efd..248afe7d 100644 --- a/route/route.go +++ b/route/route.go @@ -17,7 +17,6 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/route/rule" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing-mux" "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common" @@ -325,22 +324,23 @@ func (r *Router) matchRule( metadata.ProcessInfo = processInfo } } - if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) { - domain, loaded := r.fakeIPStore.Lookup(metadata.Destination.Addr) + if metadata.Destination.Addr.IsValid() && r.dnsTransport.FakeIP() != nil && r.dnsTransport.FakeIP().Store().Contains(metadata.Destination.Addr) { + domain, loaded := r.dnsTransport.FakeIP().Store().Lookup(metadata.Destination.Addr) if !loaded { - fatalErr = E.New("missing fakeip record, try to configure experimental.cache_file") + fatalErr = E.New("missing fakeip record, try enable `experimental.cache_file`") return } - metadata.OriginDestination = metadata.Destination - metadata.Destination = M.Socksaddr{ - Fqdn: domain, - Port: metadata.Destination.Port, + if domain != "" { + metadata.OriginDestination = metadata.Destination + metadata.Destination = M.Socksaddr{ + Fqdn: domain, + Port: metadata.Destination.Port, + } + metadata.FakeIP = true + r.logger.DebugContext(ctx, "found fakeip domain: ", domain) } - metadata.FakeIP = true - r.logger.DebugContext(ctx, "found fakeip domain: ", domain) - } - if r.dnsReverseMapping != nil && metadata.Domain == "" { - domain, loaded := r.dnsReverseMapping.Query(metadata.Destination.Addr) + } else if metadata.Domain == "" { + domain, loaded := r.dns.LookupReverseMapping(metadata.Destination.Addr) if loaded { metadata.Domain = domain r.logger.DebugContext(ctx, "found reserve mapped domain: ", metadata.Domain) @@ -369,9 +369,9 @@ func (r *Router) matchRule( packetBuffers = newPackerBuffers } } - if dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS { + if C.DomainStrategy(metadata.InboundOptions.DomainStrategy) != C.DomainStrategyAsIS { fatalErr = r.actionResolve(ctx, metadata, &rule.RuleActionResolve{ - Strategy: dns.DomainStrategy(metadata.InboundOptions.DomainStrategy), + Strategy: C.DomainStrategy(metadata.InboundOptions.DomainStrategy), }) if fatalErr != nil { return @@ -653,13 +653,23 @@ func (r *Router) actionSniff( func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundContext, action *rule.RuleActionResolve) error { if metadata.Destination.IsFqdn() { - metadata.DNSServer = action.Server - addresses, err := r.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, action.Strategy) + var transport adapter.DNSTransport + if action.Server != "" { + var loaded bool + transport, loaded = r.dnsTransport.Transport(action.Server) + if !loaded { + return E.New("DNS server not found: ", action.Server) + } + } + addresses, err := r.dns.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, adapter.DNSQueryOptions{ + Transport: transport, + Strategy: action.Strategy, + }) if err != nil { return err } metadata.DestinationAddresses = addresses - r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") + r.logger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") if metadata.Destination.IsIPv4() { metadata.IPVersion = 4 } else if metadata.Destination.IsIPv6() { diff --git a/route/route_dns.go b/route/route_dns.go deleted file mode 100644 index 3d7dc64f..00000000 --- a/route/route_dns.go +++ /dev/null @@ -1,348 +0,0 @@ -package route - -import ( - "context" - "errors" - "net/netip" - "strings" - "time" - - "github.com/sagernet/sing-box/adapter" - C "github.com/sagernet/sing-box/constant" - R "github.com/sagernet/sing-box/route/rule" - "github.com/sagernet/sing-dns" - "github.com/sagernet/sing-tun" - "github.com/sagernet/sing/common/cache" - E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" - M "github.com/sagernet/sing/common/metadata" - - mDNS "github.com/miekg/dns" -) - -type DNSReverseMapping struct { - cache *cache.LruCache[netip.Addr, string] -} - -func NewDNSReverseMapping() *DNSReverseMapping { - return &DNSReverseMapping{ - cache: cache.New[netip.Addr, string](), - } -} - -func (m *DNSReverseMapping) Save(address netip.Addr, domain string, ttl int) { - m.cache.StoreWithExpire(address, domain, time.Now().Add(time.Duration(ttl)*time.Second)) -} - -func (m *DNSReverseMapping) Query(address netip.Addr) (string, bool) { - domain, loaded := m.cache.Load(address) - return domain, loaded -} - -func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int, isAddressQuery bool) (dns.Transport, dns.QueryOptions, adapter.DNSRule, int) { - metadata := adapter.ContextFrom(ctx) - if metadata == nil { - panic("no context") - } - var options dns.QueryOptions - var currentRuleIndex int - if ruleIndex != -1 { - currentRuleIndex = ruleIndex + 1 - } - for ; currentRuleIndex < len(r.dnsRules); currentRuleIndex++ { - currentRule := r.dnsRules[currentRuleIndex] - if currentRule.WithAddressLimit() && !isAddressQuery { - continue - } - metadata.ResetRuleCache() - if currentRule.Match(metadata) { - ruleDescription := currentRule.String() - if ruleDescription != "" { - r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] ", currentRule, " => ", currentRule.Action()) - } else { - r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] => ", currentRule.Action()) - } - switch action := currentRule.Action().(type) { - case *R.RuleActionDNSRoute: - transport, loaded := r.transportMap[action.Server] - if !loaded { - r.dnsLogger.ErrorContext(ctx, "transport not found: ", action.Server) - continue - } - _, isFakeIP := transport.(adapter.FakeIPTransport) - if isFakeIP && !allowFakeIP { - continue - } - if isFakeIP || action.DisableCache { - options.DisableCache = true - } - if action.RewriteTTL != nil { - options.RewriteTTL = action.RewriteTTL - } - if action.ClientSubnet.IsValid() { - options.ClientSubnet = action.ClientSubnet - } - if domainStrategy, dsLoaded := r.transportDomainStrategy[transport]; dsLoaded { - options.Strategy = domainStrategy - } else { - options.Strategy = r.defaultDomainStrategy - } - r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] => ", currentRule.Action()) - return transport, options, currentRule, currentRuleIndex - case *R.RuleActionDNSRouteOptions: - if action.DisableCache { - options.DisableCache = true - } - if action.RewriteTTL != nil { - options.RewriteTTL = action.RewriteTTL - } - if action.ClientSubnet.IsValid() { - options.ClientSubnet = action.ClientSubnet - } - r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] => ", currentRule.Action()) - case *R.RuleActionReject: - r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] => ", currentRule.Action()) - return nil, options, currentRule, currentRuleIndex - } - } - } - if domainStrategy, dsLoaded := r.transportDomainStrategy[r.defaultTransport]; dsLoaded { - options.Strategy = domainStrategy - } else { - options.Strategy = r.defaultDomainStrategy - } - return r.defaultTransport, options, nil, -1 -} - -func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { - if len(message.Question) != 1 { - r.dnsLogger.WarnContext(ctx, "bad question size: ", len(message.Question)) - responseMessage := mDNS.Msg{ - MsgHdr: mDNS.MsgHdr{ - Id: message.Id, - Response: true, - Rcode: mDNS.RcodeFormatError, - }, - Question: message.Question, - } - return &responseMessage, nil - } - var ( - response *mDNS.Msg - cached bool - transport dns.Transport - err error - ) - response, cached = r.dnsClient.ExchangeCache(ctx, message) - if !cached { - var metadata *adapter.InboundContext - ctx, metadata = adapter.ExtendContext(ctx) - metadata.Destination = M.Socksaddr{} - metadata.QueryType = message.Question[0].Qtype - switch metadata.QueryType { - case mDNS.TypeA: - metadata.IPVersion = 4 - case mDNS.TypeAAAA: - metadata.IPVersion = 6 - } - metadata.Domain = fqdnToDomain(message.Question[0].Name) - var ( - options dns.QueryOptions - rule adapter.DNSRule - ruleIndex int - ) - ruleIndex = -1 - for { - dnsCtx := adapter.OverrideContext(ctx) - var addressLimit bool - transport, options, rule, ruleIndex = r.matchDNS(ctx, true, ruleIndex, isAddressQuery(message)) - if rule != nil { - switch action := rule.Action().(type) { - case *R.RuleActionReject: - switch action.Method { - case C.RuleActionRejectMethodDefault: - return dns.FixedResponse(message.Id, message.Question[0], nil, 0), nil - case C.RuleActionRejectMethodDrop: - return nil, tun.ErrDrop - } - } - } - r.dnsLogger.DebugContext(ctx, "exchange ", formatQuestion(message.Question[0].String()), " via ", transport.Name()) - if rule != nil && rule.WithAddressLimit() { - addressLimit = true - response, err = r.dnsClient.ExchangeWithResponseCheck(dnsCtx, transport, message, options, func(responseAddrs []netip.Addr) bool { - metadata.DestinationAddresses = responseAddrs - return rule.MatchAddressLimit(metadata) - }) - } else { - addressLimit = false - response, err = r.dnsClient.Exchange(dnsCtx, transport, message, options) - } - var rejected bool - if err != nil { - if errors.Is(err, dns.ErrResponseRejectedCached) { - rejected = true - r.dnsLogger.DebugContext(ctx, E.Cause(err, "response rejected for ", formatQuestion(message.Question[0].String())), " (cached)") - } else if errors.Is(err, dns.ErrResponseRejected) { - rejected = true - r.dnsLogger.DebugContext(ctx, E.Cause(err, "response rejected for ", formatQuestion(message.Question[0].String()))) - } else if len(message.Question) > 0 { - r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", formatQuestion(message.Question[0].String()))) - } else { - r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ")) - } - } - if addressLimit && rejected { - continue - } - break - } - } - if err != nil { - return nil, err - } - if r.dnsReverseMapping != nil && response != nil && len(response.Answer) > 0 { - if _, isFakeIP := transport.(adapter.FakeIPTransport); !isFakeIP { - for _, answer := range response.Answer { - switch record := answer.(type) { - case *mDNS.A: - r.dnsReverseMapping.Save(M.AddrFromIP(record.A), fqdnToDomain(record.Hdr.Name), int(record.Hdr.Ttl)) - case *mDNS.AAAA: - r.dnsReverseMapping.Save(M.AddrFromIP(record.AAAA), fqdnToDomain(record.Hdr.Name), int(record.Hdr.Ttl)) - } - } - } - } - return response, nil -} - -func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) { - var ( - responseAddrs []netip.Addr - cached bool - err error - ) - printResult := func() { - if err != nil { - if errors.Is(err, dns.ErrResponseRejectedCached) { - r.dnsLogger.DebugContext(ctx, "response rejected for ", domain, " (cached)") - } else if errors.Is(err, dns.ErrResponseRejected) { - r.dnsLogger.DebugContext(ctx, "response rejected for ", domain) - } else { - r.dnsLogger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain)) - } - } else if len(responseAddrs) == 0 { - r.dnsLogger.ErrorContext(ctx, "lookup failed for ", domain, ": empty result") - err = dns.RCodeNameError - } - } - responseAddrs, cached = r.dnsClient.LookupCache(ctx, domain, strategy) - if cached { - if len(responseAddrs) == 0 { - return nil, dns.RCodeNameError - } - return responseAddrs, nil - } - r.dnsLogger.DebugContext(ctx, "lookup domain ", domain) - ctx, metadata := adapter.ExtendContext(ctx) - metadata.Destination = M.Socksaddr{} - metadata.Domain = domain - if metadata.DNSServer != "" { - transport, loaded := r.transportMap[metadata.DNSServer] - if !loaded { - return nil, E.New("transport not found: ", metadata.DNSServer) - } - if strategy == dns.DomainStrategyAsIS { - if transportDomainStrategy, loaded := r.transportDomainStrategy[transport]; loaded { - strategy = transportDomainStrategy - } else { - strategy = r.defaultDomainStrategy - } - } - responseAddrs, err = r.dnsClient.Lookup(ctx, transport, domain, dns.QueryOptions{Strategy: strategy}) - } else { - var ( - transport dns.Transport - options dns.QueryOptions - rule adapter.DNSRule - ruleIndex int - ) - ruleIndex = -1 - for { - dnsCtx := adapter.OverrideContext(ctx) - var addressLimit bool - transport, options, rule, ruleIndex = r.matchDNS(ctx, false, ruleIndex, true) - if strategy != dns.DomainStrategyAsIS { - options.Strategy = strategy - } - if rule != nil { - switch action := rule.Action().(type) { - case *R.RuleActionReject: - switch action.Method { - case C.RuleActionRejectMethodDefault: - return nil, nil - case C.RuleActionRejectMethodDrop: - return nil, tun.ErrDrop - } - } - } - if rule != nil && rule.WithAddressLimit() { - addressLimit = true - responseAddrs, err = r.dnsClient.LookupWithResponseCheck(dnsCtx, transport, domain, options, func(responseAddrs []netip.Addr) bool { - metadata.DestinationAddresses = responseAddrs - return rule.MatchAddressLimit(metadata) - }) - } else { - addressLimit = false - responseAddrs, err = r.dnsClient.Lookup(dnsCtx, transport, domain, options) - } - if !addressLimit || err == nil { - break - } - printResult() - } - } - printResult() - if len(responseAddrs) > 0 { - r.dnsLogger.InfoContext(ctx, "lookup succeed for ", domain, ": ", strings.Join(F.MapToString(responseAddrs), " ")) - } - return responseAddrs, err -} - -func (r *Router) LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error) { - return r.Lookup(ctx, domain, dns.DomainStrategyAsIS) -} - -func (r *Router) ClearDNSCache() { - r.dnsClient.ClearCache() - if r.platformInterface != nil { - r.platformInterface.ClearDNSCache() - } -} - -func isAddressQuery(message *mDNS.Msg) bool { - for _, question := range message.Question { - if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA || question.Qtype == mDNS.TypeHTTPS { - return true - } - } - return false -} - -func fqdnToDomain(fqdn string) string { - if mDNS.IsFqdn(fqdn) { - return fqdn[:len(fqdn)-1] - } - return fqdn -} - -func formatQuestion(string string) string { - if strings.HasPrefix(string, ";") { - string = string[1:] - } - string = strings.ReplaceAll(string, "\t", " ") - for strings.Contains(string, " ") { - string = strings.ReplaceAll(string, " ", " ") - } - return string -} diff --git a/route/router.go b/route/router.go index 68f5dc35..63fc7b10 100644 --- a/route/router.go +++ b/route/router.go @@ -2,17 +2,10 @@ package route import ( "context" - "net/netip" - "net/url" "os" "runtime" - "strings" - "time" "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/dialer" - "github.com/sagernet/sing-box/common/geoip" - "github.com/sagernet/sing-box/common/geosite" "github.com/sagernet/sing-box/common/process" "github.com/sagernet/sing-box/common/taskmonitor" C "github.com/sagernet/sing-box/constant" @@ -20,13 +13,7 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" R "github.com/sagernet/sing-box/route/rule" - "github.com/sagernet/sing-box/transport/fakeip" - "github.com/sagernet/sing-dns" - "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/task" "github.com/sagernet/sing/service" "github.com/sagernet/sing/service/pause" @@ -35,334 +22,71 @@ import ( var _ adapter.Router = (*Router)(nil) type Router struct { - ctx context.Context - logger log.ContextLogger - dnsLogger log.ContextLogger - inbound adapter.InboundManager - outbound adapter.OutboundManager - connection adapter.ConnectionManager - network adapter.NetworkManager - rules []adapter.Rule - needGeoIPDatabase bool - needGeositeDatabase bool - geoIPOptions option.GeoIPOptions - geositeOptions option.GeositeOptions - geoIPReader *geoip.Reader - geositeReader *geosite.Reader - geositeCache map[string]adapter.Rule - needFindProcess bool - dnsClient *dns.Client - defaultDomainStrategy dns.DomainStrategy - dnsRules []adapter.DNSRule - ruleSets []adapter.RuleSet - ruleSetMap map[string]adapter.RuleSet - defaultTransport dns.Transport - transports []dns.Transport - transportMap map[string]dns.Transport - transportDomainStrategy map[dns.Transport]dns.DomainStrategy - dnsReverseMapping *DNSReverseMapping - fakeIPStore adapter.FakeIPStore - processSearcher process.Searcher - pauseManager pause.Manager - tracker adapter.ConnectionTracker - platformInterface platform.Interface - needWIFIState bool - started bool + ctx context.Context + logger log.ContextLogger + inbound adapter.InboundManager + outbound adapter.OutboundManager + dns adapter.DNSRouter + dnsTransport adapter.DNSTransportManager + connection adapter.ConnectionManager + network adapter.NetworkManager + rules []adapter.Rule + needFindProcess bool + ruleSets []adapter.RuleSet + ruleSetMap map[string]adapter.RuleSet + processSearcher process.Searcher + pauseManager pause.Manager + tracker adapter.ConnectionTracker + platformInterface platform.Interface + needWIFIState bool + started bool } -func NewRouter(ctx context.Context, logFactory log.Factory, options option.RouteOptions, dnsOptions option.DNSOptions) (*Router, error) { - router := &Router{ - ctx: ctx, - logger: logFactory.NewLogger("router"), - dnsLogger: logFactory.NewLogger("dns"), - inbound: service.FromContext[adapter.InboundManager](ctx), - outbound: service.FromContext[adapter.OutboundManager](ctx), - connection: service.FromContext[adapter.ConnectionManager](ctx), - network: service.FromContext[adapter.NetworkManager](ctx), - rules: make([]adapter.Rule, 0, len(options.Rules)), - dnsRules: make([]adapter.DNSRule, 0, len(dnsOptions.Rules)), - ruleSetMap: make(map[string]adapter.RuleSet), - needGeoIPDatabase: hasRule(options.Rules, isGeoIPRule) || hasDNSRule(dnsOptions.Rules, isGeoIPDNSRule), - needGeositeDatabase: hasRule(options.Rules, isGeositeRule) || hasDNSRule(dnsOptions.Rules, isGeositeDNSRule), - geoIPOptions: common.PtrValueOrDefault(options.GeoIP), - geositeOptions: common.PtrValueOrDefault(options.Geosite), - geositeCache: make(map[string]adapter.Rule), - needFindProcess: hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess, - defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy), - pauseManager: service.FromContext[pause.Manager](ctx), - platformInterface: service.FromContext[platform.Interface](ctx), - needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule), - } - service.MustRegister[adapter.Router](ctx, router) - router.dnsClient = dns.NewClient(dns.ClientOptions{ - DisableCache: dnsOptions.DNSClientOptions.DisableCache, - DisableExpire: dnsOptions.DNSClientOptions.DisableExpire, - IndependentCache: dnsOptions.DNSClientOptions.IndependentCache, - CacheCapacity: dnsOptions.DNSClientOptions.CacheCapacity, - RDRC: func() dns.RDRCStore { - cacheFile := service.FromContext[adapter.CacheFile](ctx) - if cacheFile == nil { - return nil - } - if !cacheFile.StoreRDRC() { - return nil - } - return cacheFile - }, - Logger: router.dnsLogger, - }) - for i, ruleOptions := range options.Rules { - routeRule, err := R.NewRule(ctx, router.logger, ruleOptions, true) - if err != nil { - return nil, E.Cause(err, "parse rule[", i, "]") - } - router.rules = append(router.rules, routeRule) - } - for i, dnsRuleOptions := range dnsOptions.Rules { - dnsRule, err := R.NewDNSRule(ctx, router.logger, dnsRuleOptions, true) - if err != nil { - return nil, E.Cause(err, "parse dns rule[", i, "]") - } - router.dnsRules = append(router.dnsRules, dnsRule) - } - for i, ruleSetOptions := range options.RuleSet { - if _, exists := router.ruleSetMap[ruleSetOptions.Tag]; exists { - return nil, E.New("duplicate rule-set tag: ", ruleSetOptions.Tag) - } - ruleSet, err := R.NewRuleSet(ctx, router.logger, ruleSetOptions) - if err != nil { - return nil, E.Cause(err, "parse rule-set[", i, "]") - } - router.ruleSets = append(router.ruleSets, ruleSet) - router.ruleSetMap[ruleSetOptions.Tag] = ruleSet +func NewRouter(ctx context.Context, logFactory log.Factory, options option.RouteOptions, dnsOptions option.DNSOptions) *Router { + return &Router{ + ctx: ctx, + logger: logFactory.NewLogger("router"), + inbound: service.FromContext[adapter.InboundManager](ctx), + outbound: service.FromContext[adapter.OutboundManager](ctx), + dns: service.FromContext[adapter.DNSRouter](ctx), + dnsTransport: service.FromContext[adapter.DNSTransportManager](ctx), + connection: service.FromContext[adapter.ConnectionManager](ctx), + network: service.FromContext[adapter.NetworkManager](ctx), + rules: make([]adapter.Rule, 0, len(options.Rules)), + ruleSetMap: make(map[string]adapter.RuleSet), + needFindProcess: hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess, + pauseManager: service.FromContext[pause.Manager](ctx), + platformInterface: service.FromContext[platform.Interface](ctx), + needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule), } +} - transports := make([]dns.Transport, len(dnsOptions.Servers)) - dummyTransportMap := make(map[string]dns.Transport) - transportMap := make(map[string]dns.Transport) - transportTags := make([]string, len(dnsOptions.Servers)) - transportTagMap := make(map[string]bool) - transportDomainStrategy := make(map[dns.Transport]dns.DomainStrategy) - for i, server := range dnsOptions.Servers { - var tag string - if server.Tag != "" { - tag = server.Tag - } else { - tag = F.ToString(i) +func (r *Router) Initialize(rules []option.Rule, ruleSets []option.RuleSet) error { + for i, options := range rules { + rule, err := R.NewRule(r.ctx, r.logger, options, false) + if err != nil { + return E.Cause(err, "parse rule[", i, "]") } - if transportTagMap[tag] { - return nil, E.New("duplicate dns server tag: ", tag) - } - transportTags[i] = tag - transportTagMap[tag] = true + r.rules = append(r.rules, rule) } - outboundManager := service.FromContext[adapter.OutboundManager](ctx) - for { - lastLen := len(dummyTransportMap) - for i, server := range dnsOptions.Servers { - tag := transportTags[i] - if _, exists := dummyTransportMap[tag]; exists { - continue - } - var detour N.Dialer - if server.Detour == "" { - detour = dialer.NewDefaultOutbound(outboundManager) - } else { - detour = dialer.NewDetour(outboundManager, server.Detour) - } - var serverProtocol string - switch server.Address { - case "local": - serverProtocol = "local" - default: - serverURL, _ := url.Parse(server.Address) - var serverAddress string - if serverURL != nil { - if serverURL.Scheme == "" { - serverProtocol = "udp" - } else { - serverProtocol = serverURL.Scheme - } - serverAddress = serverURL.Hostname() - } - if serverAddress == "" { - serverAddress = server.Address - } - notIpAddress := !M.ParseSocksaddr(serverAddress).Addr.IsValid() - if server.AddressResolver != "" { - if !transportTagMap[server.AddressResolver] { - return nil, E.New("parse dns server[", tag, "]: address resolver not found: ", server.AddressResolver) - } - if upstream, exists := dummyTransportMap[server.AddressResolver]; exists { - detour = dns.NewDialerWrapper(detour, router.dnsClient, upstream, dns.DomainStrategy(server.AddressStrategy), time.Duration(server.AddressFallbackDelay)) - } else { - continue - } - } else if notIpAddress && strings.Contains(server.Address, ".") { - return nil, E.New("parse dns server[", tag, "]: missing address_resolver") - } - } - var clientSubnet netip.Prefix - if server.ClientSubnet != nil { - clientSubnet = netip.Prefix(common.PtrValueOrDefault(server.ClientSubnet)) - } else if dnsOptions.ClientSubnet != nil { - clientSubnet = netip.Prefix(common.PtrValueOrDefault(dnsOptions.ClientSubnet)) - } - if serverProtocol == "" { - serverProtocol = "transport" - } - transport, err := dns.CreateTransport(dns.TransportOptions{ - Context: ctx, - Logger: logFactory.NewLogger(F.ToString("dns/", serverProtocol, "[", tag, "]")), - Name: tag, - Dialer: detour, - Address: server.Address, - ClientSubnet: clientSubnet, - }) - if err != nil { - return nil, E.Cause(err, "parse dns server[", tag, "]") - } - transports[i] = transport - dummyTransportMap[tag] = transport - if server.Tag != "" { - transportMap[server.Tag] = transport - } - strategy := dns.DomainStrategy(server.Strategy) - if strategy != dns.DomainStrategyAsIS { - transportDomainStrategy[transport] = strategy - } + for i, options := range ruleSets { + if _, exists := r.ruleSetMap[options.Tag]; exists { + return E.New("duplicate rule-set tag: ", options.Tag) } - if len(transports) == len(dummyTransportMap) { - break + ruleSet, err := R.NewRuleSet(r.ctx, r.logger, options) + if err != nil { + return E.Cause(err, "parse rule-set[", i, "]") } - if lastLen != len(dummyTransportMap) { - continue - } - unresolvedTags := common.MapIndexed(common.FilterIndexed(dnsOptions.Servers, func(index int, server option.DNSServerOptions) bool { - _, exists := dummyTransportMap[transportTags[index]] - return !exists - }), func(index int, server option.DNSServerOptions) string { - return transportTags[index] - }) - if len(unresolvedTags) == 0 { - panic(F.ToString("unexpected unresolved dns servers: ", len(transports), " ", len(dummyTransportMap), " ", len(transportMap))) - } - return nil, E.New("found circular reference in dns servers: ", strings.Join(unresolvedTags, " ")) + r.ruleSets = append(r.ruleSets, ruleSet) + r.ruleSetMap[options.Tag] = ruleSet } - var defaultTransport dns.Transport - if dnsOptions.Final != "" { - defaultTransport = dummyTransportMap[dnsOptions.Final] - if defaultTransport == nil { - return nil, E.New("default dns server not found: ", dnsOptions.Final) - } - } - if defaultTransport == nil { - if len(transports) == 0 { - transports = append(transports, common.Must1(dns.CreateTransport(dns.TransportOptions{ - Context: ctx, - Name: "local", - Address: "local", - Dialer: common.Must1(dialer.NewDefault(ctx, option.DialerOptions{})), - }))) - } - defaultTransport = transports[0] - } - if _, isFakeIP := defaultTransport.(adapter.FakeIPTransport); isFakeIP { - return nil, E.New("default DNS server cannot be fakeip") - } - router.defaultTransport = defaultTransport - router.transports = transports - router.transportMap = transportMap - router.transportDomainStrategy = transportDomainStrategy - - if dnsOptions.ReverseMapping { - router.dnsReverseMapping = NewDNSReverseMapping() - } - - if fakeIPOptions := dnsOptions.FakeIP; fakeIPOptions != nil && dnsOptions.FakeIP.Enabled { - var inet4Range netip.Prefix - var inet6Range netip.Prefix - if fakeIPOptions.Inet4Range != nil { - inet4Range = *fakeIPOptions.Inet4Range - } - if fakeIPOptions.Inet6Range != nil { - inet6Range = *fakeIPOptions.Inet6Range - } - router.fakeIPStore = fakeip.NewStore(ctx, router.logger, inet4Range, inet6Range) - } - return router, nil + return nil } func (r *Router) Start(stage adapter.StartStage) error { monitor := taskmonitor.New(r.logger, C.StartTimeout) switch stage { - case adapter.StartStateInitialize: - if r.fakeIPStore != nil { - monitor.Start("initialize fakeip store") - err := r.fakeIPStore.Start() - monitor.Finish() - if err != nil { - return err - } - } case adapter.StartStateStart: - if r.needGeoIPDatabase { - monitor.Start("initialize geoip database") - err := r.prepareGeoIPDatabase() - monitor.Finish() - if err != nil { - return err - } - } - if r.needGeositeDatabase { - monitor.Start("initialize geosite database") - err := r.prepareGeositeDatabase() - monitor.Finish() - if err != nil { - return err - } - } - if r.needGeositeDatabase { - for _, rule := range r.rules { - err := rule.UpdateGeosite() - if err != nil { - r.logger.Error("failed to initialize geosite: ", err) - } - } - for _, rule := range r.dnsRules { - err := rule.UpdateGeosite() - if err != nil { - r.logger.Error("failed to initialize geosite: ", err) - } - } - err := common.Close(r.geositeReader) - if err != nil { - return err - } - r.geositeCache = nil - r.geositeReader = nil - } - - monitor.Start("initialize DNS client") - r.dnsClient.Start() - monitor.Finish() - - for i, rule := range r.dnsRules { - monitor.Start("initialize DNS rule[", i, "]") - err := rule.Start() - monitor.Finish() - if err != nil { - return E.Cause(err, "initialize DNS rule[", i, "]") - } - } - for i, transport := range r.transports { - monitor.Start("initialize DNS transport[", i, "]") - err := transport.Start() - monitor.Finish() - if err != nil { - return E.Cause(err, "initialize DNS server[", i, "]") - } - } var cacheContext *adapter.HTTPStartContext if len(r.ruleSets) > 0 { monitor.Start("initialize rule-set") @@ -438,7 +162,7 @@ func (r *Router) Start(stage adapter.StartStage) error { r.started = true return nil case adapter.StartStateStarted: - for _, ruleSet := range r.ruleSetMap { + for _, ruleSet := range r.ruleSets { ruleSet.Cleanup() } runtime.GC() @@ -456,34 +180,6 @@ func (r *Router) Close() error { }) monitor.Finish() } - for i, rule := range r.dnsRules { - monitor.Start("close dns rule[", i, "]") - err = E.Append(err, rule.Close(), func(err error) error { - return E.Cause(err, "close dns rule[", i, "]") - }) - monitor.Finish() - } - for i, transport := range r.transports { - monitor.Start("close dns transport[", i, "]") - err = E.Append(err, transport.Close(), func(err error) error { - return E.Cause(err, "close dns transport[", i, "]") - }) - monitor.Finish() - } - if r.geoIPReader != nil { - monitor.Start("close geoip reader") - err = E.Append(err, r.geoIPReader.Close(), func(err error) error { - return E.Cause(err, "close geoip reader") - }) - monitor.Finish() - } - if r.fakeIPStore != nil { - monitor.Start("close fakeip store") - err = E.Append(err, r.fakeIPStore.Close(), func(err error) error { - return E.Cause(err, "close fakeip store") - }) - monitor.Finish() - } for i, ruleSet := range r.ruleSets { monitor.Start("close rule-set[", i, "]") err = E.Append(err, ruleSet.Close(), func(err error) error { @@ -494,10 +190,6 @@ func (r *Router) Close() error { return err } -func (r *Router) FakeIPStore() adapter.FakeIPStore { - return r.fakeIPStore -} - func (r *Router) RuleSet(tag string) (adapter.RuleSet, bool) { ruleSet, loaded := r.ruleSetMap[tag] return ruleSet, loaded @@ -517,7 +209,5 @@ func (r *Router) SetTracker(tracker adapter.ConnectionTracker) { func (r *Router) ResetNetwork() { r.network.ResetNetwork() - for _, transport := range r.transports { - transport.Reset() - } + r.dns.ResetNetwork() } diff --git a/route/rule/rule_abstract.go b/route/rule/rule_abstract.go index 6a569341..5be215e0 100644 --- a/route/rule/rule_abstract.go +++ b/route/rule/rule_abstract.go @@ -51,18 +51,6 @@ func (r *abstractDefaultRule) Close() error { return nil } -func (r *abstractDefaultRule) UpdateGeosite() error { - for _, item := range r.allItems { - if geositeItem, isSite := item.(*GeositeItem); isSite { - err := geositeItem.Update() - if err != nil { - return err - } - } - } - return nil -} - func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool { if len(r.allItems) == 0 { return true @@ -173,19 +161,6 @@ func (r *abstractLogicalRule) Type() string { return C.RuleTypeLogical } -func (r *abstractLogicalRule) UpdateGeosite() error { - for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (adapter.Rule, bool) { - rule, loaded := it.(adapter.Rule) - return rule, loaded - }) { - err := rule.UpdateGeosite() - if err != nil { - return err - } - } - return nil -} - func (r *abstractLogicalRule) Start() error { for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (interface { Start() error diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index 8989ff3c..7287ad86 100644 --- a/route/rule/rule_action.go +++ b/route/rule/rule_action.go @@ -13,7 +13,6 @@ import ( "github.com/sagernet/sing-box/common/sniff" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" @@ -85,7 +84,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti return sniffAction, sniffAction.build() case C.RuleActionTypeResolve: return &RuleActionResolve{ - Strategy: dns.DomainStrategy(action.ResolveOptions.Strategy), + Strategy: C.DomainStrategy(action.ResolveOptions.Strategy), Server: action.ResolveOptions.Server, }, nil default: @@ -101,6 +100,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction) return &RuleActionDNSRoute{ Server: action.RouteOptions.Server, RuleActionDNSRouteOptions: RuleActionDNSRouteOptions{ + Strategy: C.DomainStrategy(action.RouteOptions.Strategy), DisableCache: action.RouteOptions.DisableCache, RewriteTTL: action.RouteOptions.RewriteTTL, ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)), @@ -108,6 +108,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction) } case C.RuleActionTypeRouteOptions: return &RuleActionDNSRouteOptions{ + Strategy: C.DomainStrategy(action.RouteOptionsOptions.Strategy), DisableCache: action.RouteOptionsOptions.DisableCache, RewriteTTL: action.RouteOptionsOptions.RewriteTTL, ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptionsOptions.ClientSubnet)), @@ -214,6 +215,7 @@ func (r *RuleActionDNSRoute) String() string { } type RuleActionDNSRouteOptions struct { + Strategy C.DomainStrategy DisableCache bool RewriteTTL *uint32 ClientSubnet netip.Prefix @@ -362,7 +364,7 @@ func (r *RuleActionSniff) String() string { } type RuleActionResolve struct { - Strategy dns.DomainStrategy + Strategy C.DomainStrategy Server string } @@ -371,11 +373,11 @@ func (r *RuleActionResolve) Type() string { } func (r *RuleActionResolve) String() string { - if r.Strategy == dns.DomainStrategyAsIS && r.Server == "" { + if r.Strategy == C.DomainStrategyAsIS && r.Server == "" { return F.ToString("resolve") - } else if r.Strategy != dns.DomainStrategyAsIS && r.Server == "" { + } else if r.Strategy != C.DomainStrategyAsIS && r.Server == "" { return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ")") - } else if r.Strategy == dns.DomainStrategyAsIS && r.Server != "" { + } else if r.Strategy == C.DomainStrategyAsIS && r.Server != "" { return F.ToString("resolve(", r.Server, ")") } else { return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ",", r.Server, ")") diff --git a/route/rule/rule_default.go b/route/rule/rule_default.go index 2794c287..aa6059d2 100644 --- a/route/rule/rule_default.go +++ b/route/rule/rule_default.go @@ -120,19 +120,13 @@ func NewDefaultRule(ctx context.Context, logger log.ContextLogger, options optio rule.allItems = append(rule.allItems, item) } if len(options.Geosite) > 0 { - item := NewGeositeItem(router, logger, options.Geosite) - rule.destinationAddressItems = append(rule.destinationAddressItems, item) - rule.allItems = append(rule.allItems, item) + return nil, E.New("geosite database is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0") } if len(options.SourceGeoIP) > 0 { - item := NewGeoIPItem(router, logger, true, options.SourceGeoIP) - rule.sourceAddressItems = append(rule.sourceAddressItems, item) - rule.allItems = append(rule.allItems, item) + return nil, E.New("geoip database is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0") } if len(options.GeoIP) > 0 { - item := NewGeoIPItem(router, logger, false, options.GeoIP) - rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item) - rule.allItems = append(rule.allItems, item) + return nil, E.New("geoip database is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0") } if len(options.SourceIPCIDR) > 0 { item, err := NewIPCIDRItem(true, options.SourceIPCIDR) diff --git a/route/rule/rule_dns.go b/route/rule/rule_dns.go index fb8c6b78..9d1c69b8 100644 --- a/route/rule/rule_dns.go +++ b/route/rule/rule_dns.go @@ -111,19 +111,13 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op rule.allItems = append(rule.allItems, item) } if len(options.Geosite) > 0 { - item := NewGeositeItem(router, logger, options.Geosite) - rule.destinationAddressItems = append(rule.destinationAddressItems, item) - rule.allItems = append(rule.allItems, item) + return nil, E.New("geosite database is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0") } if len(options.SourceGeoIP) > 0 { - item := NewGeoIPItem(router, logger, true, options.SourceGeoIP) - rule.sourceAddressItems = append(rule.sourceAddressItems, item) - rule.allItems = append(rule.allItems, item) + return nil, E.New("geoip database is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0") } if len(options.GeoIP) > 0 { - item := NewGeoIPItem(router, logger, false, options.GeoIP) - rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item) - rule.allItems = append(rule.allItems, item) + return nil, E.New("geoip database is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0") } if len(options.SourceIPCIDR) > 0 { item, err := NewIPCIDRItem(true, options.SourceIPCIDR) @@ -151,6 +145,11 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item) rule.allItems = append(rule.allItems, item) } + if options.IPAcceptAny { + item := NewIPAcceptAnyItem() + rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item) + rule.allItems = append(rule.allItems, item) + } if len(options.SourcePort) > 0 { item := NewPortItem(true, options.SourcePort) rule.sourcePortItems = append(rule.sourcePortItems, item) diff --git a/route/rule/rule_item_geoip.go b/route/rule/rule_item_geoip.go deleted file mode 100644 index 3c967fec..00000000 --- a/route/rule/rule_item_geoip.go +++ /dev/null @@ -1,98 +0,0 @@ -package rule - -import ( - "net/netip" - "strings" - - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/log" - N "github.com/sagernet/sing/common/network" -) - -var _ RuleItem = (*GeoIPItem)(nil) - -type GeoIPItem struct { - router adapter.Router - logger log.ContextLogger - isSource bool - codes []string - codeMap map[string]bool -} - -func NewGeoIPItem(router adapter.Router, logger log.ContextLogger, isSource bool, codes []string) *GeoIPItem { - codeMap := make(map[string]bool) - for _, code := range codes { - codeMap[code] = true - } - return &GeoIPItem{ - router: router, - logger: logger, - codes: codes, - isSource: isSource, - codeMap: codeMap, - } -} - -func (r *GeoIPItem) Match(metadata *adapter.InboundContext) bool { - var geoipCode string - if r.isSource && metadata.SourceGeoIPCode != "" { - geoipCode = metadata.SourceGeoIPCode - } else if !r.isSource && metadata.GeoIPCode != "" { - geoipCode = metadata.GeoIPCode - } - if geoipCode != "" { - return r.codeMap[geoipCode] - } - var destination netip.Addr - if r.isSource { - destination = metadata.Source.Addr - } else { - destination = metadata.Destination.Addr - } - if destination.IsValid() { - return r.match(metadata, destination) - } - for _, destinationAddress := range metadata.DestinationAddresses { - if r.match(metadata, destinationAddress) { - return true - } - } - return false -} - -func (r *GeoIPItem) match(metadata *adapter.InboundContext, destination netip.Addr) bool { - var geoipCode string - geoReader := r.router.GeoIPReader() - if !N.IsPublicAddr(destination) { - geoipCode = "private" - } else if geoReader != nil { - geoipCode = geoReader.Lookup(destination) - } - if geoipCode == "" { - return false - } - if r.isSource { - metadata.SourceGeoIPCode = geoipCode - } else { - metadata.GeoIPCode = geoipCode - } - return r.codeMap[geoipCode] -} - -func (r *GeoIPItem) String() string { - var description string - if r.isSource { - description = "source_geoip=" - } else { - description = "geoip=" - } - cLen := len(r.codes) - if cLen == 1 { - description += r.codes[0] - } else if cLen > 3 { - description += "[" + strings.Join(r.codes[:3], " ") + "...]" - } else { - description += "[" + strings.Join(r.codes, " ") + "]" - } - return description -} diff --git a/route/rule/rule_item_geosite.go b/route/rule/rule_item_geosite.go deleted file mode 100644 index 9e5e03c8..00000000 --- a/route/rule/rule_item_geosite.go +++ /dev/null @@ -1,61 +0,0 @@ -package rule - -import ( - "strings" - - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/log" - E "github.com/sagernet/sing/common/exceptions" -) - -var _ RuleItem = (*GeositeItem)(nil) - -type GeositeItem struct { - router adapter.Router - logger log.ContextLogger - codes []string - matchers []adapter.Rule -} - -func NewGeositeItem(router adapter.Router, logger log.ContextLogger, codes []string) *GeositeItem { - return &GeositeItem{ - router: router, - logger: logger, - codes: codes, - } -} - -func (r *GeositeItem) Update() error { - matchers := make([]adapter.Rule, 0, len(r.codes)) - for _, code := range r.codes { - matcher, err := r.router.LoadGeosite(code) - if err != nil { - return E.Cause(err, "read geosite") - } - matchers = append(matchers, matcher) - } - r.matchers = matchers - return nil -} - -func (r *GeositeItem) Match(metadata *adapter.InboundContext) bool { - for _, matcher := range r.matchers { - if matcher.Match(metadata) { - return true - } - } - return false -} - -func (r *GeositeItem) String() string { - description := "geosite=" - cLen := len(r.codes) - if cLen == 1 { - description += r.codes[0] - } else if cLen > 3 { - description += "[" + strings.Join(r.codes[:3], " ") + "...]" - } else { - description += "[" + strings.Join(r.codes, " ") + "]" - } - return description -} diff --git a/route/rule/rule_item_ip_accept_any.go b/route/rule/rule_item_ip_accept_any.go new file mode 100644 index 00000000..1ca71257 --- /dev/null +++ b/route/rule/rule_item_ip_accept_any.go @@ -0,0 +1,21 @@ +package rule + +import ( + "github.com/sagernet/sing-box/adapter" +) + +var _ RuleItem = (*IPAcceptAnyItem)(nil) + +type IPAcceptAnyItem struct{} + +func NewIPAcceptAnyItem() *IPAcceptAnyItem { + return &IPAcceptAnyItem{} +} + +func (r *IPAcceptAnyItem) Match(metadata *adapter.InboundContext) bool { + return len(metadata.DestinationAddresses) > 0 +} + +func (r *IPAcceptAnyItem) String() string { + return "ip_accept_any=true" +} diff --git a/route/rule_conds.go b/route/rule_conds.go index 76447176..55c4a058 100644 --- a/route/rule_conds.go +++ b/route/rule_conds.go @@ -3,7 +3,6 @@ package route import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing/common" ) func hasRule(rules []option.Rule, cond func(rule option.DefaultRule) bool) bool { @@ -38,22 +37,6 @@ func hasDNSRule(rules []option.DNSRule, cond func(rule option.DefaultDNSRule) bo return false } -func isGeoIPRule(rule option.DefaultRule) bool { - return len(rule.SourceGeoIP) > 0 && common.Any(rule.SourceGeoIP, notPrivateNode) || len(rule.GeoIP) > 0 && common.Any(rule.GeoIP, notPrivateNode) -} - -func isGeoIPDNSRule(rule option.DefaultDNSRule) bool { - return len(rule.SourceGeoIP) > 0 && common.Any(rule.SourceGeoIP, notPrivateNode) || len(rule.GeoIP) > 0 && common.Any(rule.GeoIP, notPrivateNode) -} - -func isGeositeRule(rule option.DefaultRule) bool { - return len(rule.Geosite) > 0 -} - -func isGeositeDNSRule(rule option.DefaultDNSRule) bool { - return len(rule.Geosite) > 0 -} - func isProcessRule(rule option.DefaultRule) bool { return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.ProcessPathRegex) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0 } @@ -62,10 +45,6 @@ func isProcessDNSRule(rule option.DefaultDNSRule) bool { return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.ProcessPathRegex) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0 } -func notPrivateNode(code string) bool { - return code != "private" -} - func isWIFIRule(rule option.DefaultRule) bool { return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0 } diff --git a/test/domain_inbound_test.go b/test/domain_inbound_test.go index f39cd187..605740d4 100644 --- a/test/domain_inbound_test.go +++ b/test/domain_inbound_test.go @@ -6,7 +6,6 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/json/badoption" @@ -34,7 +33,7 @@ func TestTUICDomainUDP(t *testing.T) { Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())), ListenPort: serverPort, InboundOptions: option.InboundOptions{ - DomainStrategy: option.DomainStrategy(dns.DomainStrategyUseIPv6), + DomainStrategy: option.DomainStrategy(C.DomainStrategyIPv6Only), }, }, Users: []option.TUICUser{{ diff --git a/transport/fakeip/server.go b/transport/fakeip/server.go deleted file mode 100644 index d1bbb2aa..00000000 --- a/transport/fakeip/server.go +++ /dev/null @@ -1,95 +0,0 @@ -package fakeip - -import ( - "context" - "net/netip" - "os" - - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-dns" - E "github.com/sagernet/sing/common/exceptions" - "github.com/sagernet/sing/common/logger" - "github.com/sagernet/sing/service" - - mDNS "github.com/miekg/dns" -) - -var ( - _ dns.Transport = (*Transport)(nil) - _ adapter.FakeIPTransport = (*Transport)(nil) -) - -func init() { - dns.RegisterTransport([]string{"fakeip"}, func(options dns.TransportOptions) (dns.Transport, error) { - return NewTransport(options) - }) -} - -type Transport struct { - name string - router adapter.Router - store adapter.FakeIPStore - logger logger.ContextLogger -} - -func NewTransport(options dns.TransportOptions) (*Transport, error) { - router := service.FromContext[adapter.Router](options.Context) - if router == nil { - return nil, E.New("missing router in context") - } - return &Transport{ - name: options.Name, - router: router, - logger: options.Logger, - }, nil -} - -func (s *Transport) Name() string { - return s.name -} - -func (s *Transport) Start() error { - s.store = s.router.FakeIPStore() - if s.store == nil { - return E.New("fakeip not enabled") - } - return nil -} - -func (s *Transport) Reset() { -} - -func (s *Transport) Close() error { - return nil -} - -func (s *Transport) Raw() bool { - return false -} - -func (s *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { - return nil, os.ErrInvalid -} - -func (s *Transport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) { - var addresses []netip.Addr - if strategy != dns.DomainStrategyUseIPv6 { - inet4Address, err := s.store.Create(domain, false) - if err != nil { - return nil, err - } - addresses = append(addresses, inet4Address) - } - if strategy != dns.DomainStrategyUseIPv4 { - inet6Address, err := s.store.Create(domain, true) - if err != nil { - return nil, err - } - addresses = append(addresses, inet6Address) - } - return addresses, nil -} - -func (s *Transport) Store() adapter.FakeIPStore { - return s.store -} diff --git a/transport/v2rayhttp/server.go b/transport/v2rayhttp/server.go index e0ee42a7..6256cd25 100644 --- a/transport/v2rayhttp/server.go +++ b/transport/v2rayhttp/server.go @@ -164,7 +164,7 @@ func (s *Server) Serve(listener net.Listener) error { if len(s.tlsConfig.NextProtos()) == 0 { s.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"}) } else if !common.Contains(s.tlsConfig.NextProtos(), http2.NextProtoTLS) { - s.tlsConfig.SetNextProtos(append([]string{"h2"}, s.tlsConfig.NextProtos()...)) + s.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, s.tlsConfig.NextProtos()...)) } listener = aTLS.NewListener(listener, s.tlsConfig) } From 42fe00ed301bfba397a1989292168a2868b100a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 12 Jan 2025 12:45:27 +0800 Subject: [PATCH 38/62] refactor: Outbound domain resolver --- adapter/network.go | 14 +-- box.go | 6 +- common/dialer/default.go | 7 -- common/dialer/detour.go | 16 ++-- common/dialer/dialer.go | 130 ++++++++++++++++++--------- common/dialer/resolve.go | 113 ++++++++++++++++++----- common/tls/reality_server.go | 2 +- dns/transport_adapter.go | 12 ++- dns/transport_dialer.go | 50 ++++++----- experimental/deprecated/constants.go | 26 +++++- option/dns.go | 50 ++++++----- option/outbound.go | 40 ++++++++- option/route.go | 1 + protocol/direct/outbound.go | 12 ++- protocol/http/outbound.go | 2 +- protocol/hysteria/outbound.go | 2 +- protocol/hysteria2/outbound.go | 2 +- protocol/shadowsocks/outbound.go | 2 +- protocol/shadowtls/inbound.go | 4 +- protocol/shadowtls/outbound.go | 2 +- protocol/socks/outbound.go | 2 +- protocol/ssh/outbound.go | 2 +- protocol/tor/outbound.go | 2 +- protocol/trojan/outbound.go | 2 +- protocol/tuic/outbound.go | 2 +- protocol/vless/outbound.go | 2 +- protocol/vmess/outbound.go | 2 +- protocol/wireguard/endpoint.go | 13 ++- protocol/wireguard/outbound.go | 13 ++- route/network.go | 13 ++- route/rule/rule_action.go | 2 +- route/rule/rule_dns.go | 2 +- route/rule/rule_item_outbound.go | 9 +- 33 files changed, 392 insertions(+), 167 deletions(-) diff --git a/adapter/network.go b/adapter/network.go index 3adfaaeb..50670831 100644 --- a/adapter/network.go +++ b/adapter/network.go @@ -29,12 +29,14 @@ type NetworkManager interface { } type NetworkOptions struct { - NetworkStrategy *C.NetworkStrategy - NetworkType []C.InterfaceType - FallbackNetworkType []C.InterfaceType - FallbackDelay time.Duration - BindInterface string - RoutingMark uint32 + BindInterface string + RoutingMark uint32 + DomainResolver string + DomainResolveOptions DNSQueryOptions + NetworkStrategy *C.NetworkStrategy + NetworkType []C.InterfaceType + FallbackNetworkType []C.InterfaceType + FallbackDelay time.Duration } type InterfaceUpdateListener interface { diff --git a/box.go b/box.go index bd15c66a..72ba43f8 100644 --- a/box.go +++ b/box.go @@ -187,7 +187,7 @@ func New(options Options) (*Box, error) { transportOptions.Options, ) if err != nil { - return nil, E.Cause(err, "initialize inbound[", i, "]") + return nil, E.Cause(err, "initialize DNS server[", i, "]") } } err = dnsRouter.Initialize(dnsOptions.Rules) @@ -210,7 +210,7 @@ func New(options Options) (*Box, error) { endpointOptions.Options, ) if err != nil { - return nil, E.Cause(err, "initialize inbound[", i, "]") + return nil, E.Cause(err, "initialize endpoint[", i, "]") } } for i, inboundOptions := range options.Inbounds { @@ -309,7 +309,7 @@ func New(options Options) (*Box, error) { } } if ntpOptions.Enabled { - ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions) + ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain()) if err != nil { return nil, E.Cause(err, "create NTP service") } diff --git a/common/dialer/default.go b/common/dialer/default.go index 77536c43..50244ac5 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -35,7 +35,6 @@ type DefaultDialer struct { udpListener net.ListenConfig udpAddr4 string udpAddr6 string - isWireGuardListener bool networkManager adapter.NetworkManager networkStrategy *C.NetworkStrategy defaultNetworkStrategy bool @@ -183,11 +182,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial } setMultiPathTCP(&dialer4) } - if options.IsWireGuardListener { - for _, controlFn := range WgControlFns { - listener.Control = control.Append(listener.Control, controlFn) - } - } tcpDialer4, err := newTCPDialer(dialer4, options.TCPFastOpen) if err != nil { return nil, err @@ -204,7 +198,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial udpListener: listener, udpAddr4: udpAddr4, udpAddr6: udpAddr6, - isWireGuardListener: options.IsWireGuardListener, networkManager: networkManager, networkStrategy: networkStrategy, defaultNetworkStrategy: defaultNetworkStrategy, diff --git a/common/dialer/detour.go b/common/dialer/detour.go index c1d40faa..e4a46049 100644 --- a/common/dialer/detour.go +++ b/common/dialer/detour.go @@ -29,16 +29,18 @@ func (d *DetourDialer) Start() error { } func (d *DetourDialer) Dialer() (N.Dialer, error) { - d.initOnce.Do(func() { - var loaded bool - d.dialer, loaded = d.outboundManager.Outbound(d.detour) - if !loaded { - d.initErr = E.New("outbound detour not found: ", d.detour) - } - }) + d.initOnce.Do(d.init) return d.dialer, d.initErr } +func (d *DetourDialer) init() { + var loaded bool + d.dialer, loaded = d.outboundManager.Outbound(d.detour) + if !loaded { + d.initErr = E.New("outbound detour not found: ", d.detour) + } +} + func (d *DetourDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { dialer, err := d.Dialer() if err != nil { diff --git a/common/dialer/dialer.go b/common/dialer/dialer.go index f63e3864..812e5575 100644 --- a/common/dialer/dialer.go +++ b/common/dialer/dialer.go @@ -8,6 +8,7 @@ import ( "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/deprecated" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -15,60 +16,105 @@ import ( "github.com/sagernet/sing/service" ) -func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) { - if options.IsWireGuardListener { - return NewDefault(ctx, options) - } +type Options struct { + Context context.Context + Options option.DialerOptions + RemoteIsDomain bool + DirectResolver bool + ResolverOnDetour bool +} + +// TODO: merge with NewWithOptions +func New(ctx context.Context, options option.DialerOptions, remoteIsDomain bool) (N.Dialer, error) { + return NewWithOptions(Options{ + Context: ctx, + Options: options, + RemoteIsDomain: remoteIsDomain, + }) +} + +func NewWithOptions(options Options) (N.Dialer, error) { + dialOptions := options.Options var ( dialer N.Dialer err error ) - if options.Detour == "" { - dialer, err = NewDefault(ctx, options) - if err != nil { - return nil, err - } - } else { - outboundManager := service.FromContext[adapter.OutboundManager](ctx) + if dialOptions.Detour != "" { + outboundManager := service.FromContext[adapter.OutboundManager](options.Context) if outboundManager == nil { return nil, E.New("missing outbound manager") } - dialer = NewDetour(outboundManager, options.Detour) - } - if options.Detour == "" { - router := service.FromContext[adapter.DNSRouter](ctx) - if router != nil { - dialer = NewResolveDialer( - router, - dialer, - options.Detour == "" && !options.TCPFastOpen, - C.DomainStrategy(options.DomainStrategy), - time.Duration(options.FallbackDelay)) + dialer = NewDetour(outboundManager, dialOptions.Detour) + } else { + dialer, err = NewDefault(options.Context, dialOptions) + if err != nil { + return nil, err } } + if options.RemoteIsDomain && (dialOptions.Detour == "" || options.ResolverOnDetour) { + networkManager := service.FromContext[adapter.NetworkManager](options.Context) + dnsTransport := service.FromContext[adapter.DNSTransportManager](options.Context) + var defaultOptions adapter.NetworkOptions + if networkManager != nil { + defaultOptions = networkManager.DefaultOptions() + } + var ( + server string + dnsQueryOptions adapter.DNSQueryOptions + resolveFallbackDelay time.Duration + ) + if dialOptions.DomainResolver != nil && dialOptions.DomainResolver.Server != "" { + var transport adapter.DNSTransport + if !options.DirectResolver { + var loaded bool + transport, loaded = dnsTransport.Transport(dialOptions.DomainResolver.Server) + if !loaded { + return nil, E.New("domain resolver not found: " + dialOptions.DomainResolver.Server) + } + } + var strategy C.DomainStrategy + if dialOptions.DomainResolver.Strategy != option.DomainStrategy(C.DomainStrategyAsIS) { + strategy = C.DomainStrategy(dialOptions.DomainResolver.Strategy) + } else if + //nolint:staticcheck + dialOptions.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) { + //nolint:staticcheck + strategy = C.DomainStrategy(dialOptions.DomainStrategy) + } + server = dialOptions.DomainResolver.Server + dnsQueryOptions = adapter.DNSQueryOptions{ + Transport: transport, + Strategy: strategy, + DisableCache: dialOptions.DomainResolver.DisableCache, + RewriteTTL: dialOptions.DomainResolver.RewriteTTL, + ClientSubnet: dialOptions.DomainResolver.ClientSubnet.Build(netip.Prefix{}), + } + resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay) + } else if options.DirectResolver { + return nil, E.New("missing domain resolver for domain server address") + } else if defaultOptions.DomainResolver != "" { + dnsQueryOptions = defaultOptions.DomainResolveOptions + transport, loaded := dnsTransport.Transport(defaultOptions.DomainResolver) + if !loaded { + return nil, E.New("default domain resolver not found: " + defaultOptions.DomainResolver) + } + dnsQueryOptions.Transport = transport + resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay) + } else { + deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver) + } + dialer = NewResolveDialer( + options.Context, + dialer, + dialOptions.Detour == "" && !dialOptions.TCPFastOpen, + server, + dnsQueryOptions, + resolveFallbackDelay, + ) + } return dialer, nil } -func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInterfaceDialer, error) { - if options.Detour != "" { - return nil, E.New("`detour` is not supported in direct context") - } - if options.IsWireGuardListener { - return NewDefault(ctx, options) - } - dialer, err := NewDefault(ctx, options) - if err != nil { - return nil, err - } - return NewResolveParallelInterfaceDialer( - service.FromContext[adapter.DNSRouter](ctx), - dialer, - true, - C.DomainStrategy(options.DomainStrategy), - time.Duration(options.FallbackDelay), - ), nil -} - type ParallelInterfaceDialer interface { N.Dialer DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) diff --git a/common/dialer/resolve.go b/common/dialer/resolve.go index 3d667a6c..66b74e3c 100644 --- a/common/dialer/resolve.go +++ b/common/dialer/resolve.go @@ -3,14 +3,17 @@ package dialer import ( "context" "net" + "sync" "time" "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common/bufio" + E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" ) var ( @@ -18,21 +21,37 @@ var ( _ ParallelInterfaceDialer = (*resolveParallelNetworkDialer)(nil) ) +type ResolveDialer interface { + N.Dialer + QueryOptions() adapter.DNSQueryOptions +} + +type ParallelInterfaceResolveDialer interface { + ParallelInterfaceDialer + QueryOptions() adapter.DNSQueryOptions +} + type resolveDialer struct { + transport adapter.DNSTransportManager + router adapter.DNSRouter dialer N.Dialer parallel bool - router adapter.DNSRouter - strategy C.DomainStrategy + server string + initOnce sync.Once + initErr error + queryOptions adapter.DNSQueryOptions fallbackDelay time.Duration } -func NewResolveDialer(router adapter.DNSRouter, dialer N.Dialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer { +func NewResolveDialer(ctx context.Context, dialer N.Dialer, parallel bool, server string, queryOptions adapter.DNSQueryOptions, fallbackDelay time.Duration) ResolveDialer { return &resolveDialer{ - dialer, - parallel, - router, - strategy, - fallbackDelay, + transport: service.FromContext[adapter.DNSTransportManager](ctx), + router: service.FromContext[adapter.DNSRouter](ctx), + dialer: dialer, + parallel: parallel, + server: server, + queryOptions: queryOptions, + fallbackDelay: fallbackDelay, } } @@ -41,41 +60,68 @@ type resolveParallelNetworkDialer struct { dialer ParallelInterfaceDialer } -func NewResolveParallelInterfaceDialer(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer { +func NewResolveParallelInterfaceDialer(ctx context.Context, dialer ParallelInterfaceDialer, parallel bool, server string, queryOptions adapter.DNSQueryOptions, fallbackDelay time.Duration) ParallelInterfaceResolveDialer { return &resolveParallelNetworkDialer{ resolveDialer{ - dialer, - parallel, - router, - strategy, - fallbackDelay, + transport: service.FromContext[adapter.DNSTransportManager](ctx), + router: service.FromContext[adapter.DNSRouter](ctx), + dialer: dialer, + parallel: parallel, + server: server, + queryOptions: queryOptions, + fallbackDelay: fallbackDelay, }, dialer, } } +func (d *resolveDialer) initialize() error { + d.initOnce.Do(d.initServer) + return d.initErr +} + +func (d *resolveDialer) initServer() { + if d.server == "" { + return + } + transport, loaded := d.transport.Transport(d.server) + if !loaded { + d.initErr = E.New("domain resolver not found: " + d.server) + return + } + d.queryOptions.Transport = transport +} + func (d *resolveDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + err := d.initialize() + if err != nil { + return nil, err + } if !destination.IsFqdn() { return d.dialer.DialContext(ctx, network, destination) } ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy}) + addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions) if err != nil { return nil, err } if d.parallel { - return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay) + return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.queryOptions.Strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay) } else { return N.DialSerial(ctx, d.dialer, network, destination, addresses) } } func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + err := d.initialize() + if err != nil { + return nil, err + } if !destination.IsFqdn() { return d.dialer.ListenPacket(ctx, destination) } ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy}) + addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions) if err != nil { return nil, err } @@ -86,14 +132,24 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil } +func (d *resolveDialer) QueryOptions() adapter.DNSQueryOptions { + return d.queryOptions +} + +func (d *resolveDialer) Upstream() any { + return d.dialer +} + func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { + err := d.initialize() + if err != nil { + return nil, err + } if !destination.IsFqdn() { return d.dialer.DialContext(ctx, network, destination) } ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{ - Strategy: d.strategy, - }) + addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions) if err != nil { return nil, err } @@ -101,21 +157,28 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context fallbackDelay = d.fallbackDelay } if d.parallel { - return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) + return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.queryOptions.Strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) } else { return DialSerialNetwork(ctx, d.dialer, network, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) } } func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) { + err := d.initialize() + if err != nil { + return nil, err + } if !destination.IsFqdn() { return d.dialer.ListenPacket(ctx, destination) } ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) - addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy}) + addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions) if err != nil { return nil, err } + if fallbackDelay == 0 { + fallbackDelay = d.fallbackDelay + } conn, destinationAddress, err := ListenSerialNetworkPacket(ctx, d.dialer, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) if err != nil { return nil, err @@ -123,6 +186,10 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil } -func (d *resolveDialer) Upstream() any { +func (d *resolveParallelNetworkDialer) QueryOptions() adapter.DNSQueryOptions { + return d.queryOptions +} + +func (d *resolveParallelNetworkDialer) Upstream() any { return d.dialer } diff --git a/common/tls/reality_server.go b/common/tls/reality_server.go index cf429815..912d13dd 100644 --- a/common/tls/reality_server.go +++ b/common/tls/reality_server.go @@ -101,7 +101,7 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb tlsConfig.ShortIds[shortID] = true } - handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions) + handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions, options.Reality.Handshake.ServerIsDomain()) if err != nil { return nil, err } diff --git a/dns/transport_adapter.go b/dns/transport_adapter.go index 02c84621..47345709 100644 --- a/dns/transport_adapter.go +++ b/dns/transport_adapter.go @@ -27,9 +27,14 @@ func NewTransportAdapter(transportType string, transportTag string, dependencies } func NewTransportAdapterWithLocalOptions(transportType string, transportTag string, localOptions option.LocalDNSServerOptions) TransportAdapter { + var dependencies []string + if localOptions.DomainResolver != nil && localOptions.DomainResolver.Server != "" { + dependencies = append(dependencies, localOptions.DomainResolver.Server) + } return TransportAdapter{ transportType: transportType, transportTag: transportTag, + dependencies: dependencies, strategy: C.DomainStrategy(localOptions.LegacyStrategy), clientSubnet: localOptions.LegacyClientSubnet, } @@ -37,8 +42,11 @@ func NewTransportAdapterWithLocalOptions(transportType string, transportTag stri func NewTransportAdapterWithRemoteOptions(transportType string, transportTag string, remoteOptions option.RemoteDNSServerOptions) TransportAdapter { var dependencies []string - if remoteOptions.AddressResolver != "" { - dependencies = []string{remoteOptions.AddressResolver} + if remoteOptions.DomainResolver != nil && remoteOptions.DomainResolver.Server != "" { + dependencies = append(dependencies, remoteOptions.DomainResolver.Server) + } + if remoteOptions.LegacyAddressResolver != "" { + dependencies = append(dependencies, remoteOptions.LegacyAddressResolver) } return TransportAdapter{ transportType: transportType, diff --git a/dns/transport_dialer.go b/dns/transport_dialer.go index 14e1188d..0b15c7ea 100644 --- a/dns/transport_dialer.go +++ b/dns/transport_dialer.go @@ -19,29 +19,39 @@ func NewLocalDialer(ctx context.Context, options option.LocalDNSServerOptions) ( if options.LegacyDefaultDialer { return dialer.NewDefaultOutbound(ctx), nil } else { - return dialer.New(ctx, options.DialerOptions) + return dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.DialerOptions, + DirectResolver: true, + }) } } func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions) (N.Dialer, error) { - transportDialer, err := NewLocalDialer(ctx, options.LocalDNSServerOptions) - if err != nil { - return nil, err - } - if options.AddressResolver != "" { - transport := service.FromContext[adapter.DNSTransportManager](ctx) - resolverTransport, loaded := transport.Transport(options.AddressResolver) - if !loaded { - return nil, E.New("address resolver not found: ", options.AddressResolver) + if options.LegacyDefaultDialer { + transportDialer := dialer.NewDefaultOutbound(ctx) + if options.LegacyAddressResolver != "" { + transport := service.FromContext[adapter.DNSTransportManager](ctx) + resolverTransport, loaded := transport.Transport(options.LegacyAddressResolver) + if !loaded { + return nil, E.New("address resolver not found: ", options.LegacyAddressResolver) + } + transportDialer = newTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.LegacyAddressStrategy), time.Duration(options.LegacyAddressFallbackDelay)) + } else if options.ServerIsDomain() { + return nil, E.New("missing address resolver for server: ", options.Server) } - transportDialer = NewTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.AddressStrategy), time.Duration(options.AddressFallbackDelay)) - } else if M.IsDomainName(options.Server) { - return nil, E.New("missing address resolver for server: ", options.Server) + return transportDialer, nil + } else { + return dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.DialerOptions, + RemoteIsDomain: options.ServerIsDomain(), + DirectResolver: true, + }) } - return transportDialer, nil } -type TransportDialer struct { +type legacyTransportDialer struct { dialer N.Dialer dnsRouter adapter.DNSRouter transport adapter.DNSTransport @@ -49,8 +59,8 @@ type TransportDialer struct { fallbackDelay time.Duration } -func NewTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) *TransportDialer { - return &TransportDialer{ +func newTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) *legacyTransportDialer { + return &legacyTransportDialer{ dialer, dnsRouter, transport, @@ -59,7 +69,7 @@ func NewTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport } } -func (d *TransportDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { +func (d *legacyTransportDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { if destination.IsIP() { return d.dialer.DialContext(ctx, network, destination) } @@ -73,7 +83,7 @@ func (d *TransportDialer) DialContext(ctx context.Context, network string, desti return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay) } -func (d *TransportDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { +func (d *legacyTransportDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { if destination.IsIP() { return d.dialer.ListenPacket(ctx, destination) } @@ -88,6 +98,6 @@ func (d *TransportDialer) ListenPacket(ctx context.Context, destination M.Socksa return conn, err } -func (d *TransportDialer) Upstream() any { +func (d *legacyTransportDialer) Upstream() any { return d.dialer } diff --git a/experimental/deprecated/constants.go b/experimental/deprecated/constants.go index bf648365..d5c3ca48 100644 --- a/experimental/deprecated/constants.go +++ b/experimental/deprecated/constants.go @@ -148,10 +148,11 @@ var OptionTUNGSO = Note{ var OptionLegacyDNSTransport = Note{ Name: "legacy-dns-transport", - Description: "legacy DNS transport", + Description: "legacy DNS servers", DeprecatedVersion: "1.12.0", ScheduledVersion: "1.14.0", - EnvName: "LEGACY_DNS_TRANSPORT", + EnvName: "LEGACY_DNS_SERVERS", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats", } var OptionLegacyDNSFakeIPOptions = Note{ @@ -159,6 +160,23 @@ var OptionLegacyDNSFakeIPOptions = Note{ Description: "legacy DNS fakeip options", DeprecatedVersion: "1.12.0", ScheduledVersion: "1.14.0", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats", +} + +var OptionOutboundDNSRuleItem = Note{ + Name: "outbound-dns-rule-item", + Description: "outbound DNS rule item", + DeprecatedVersion: "1.12.0", + ScheduledVersion: "1.14.0", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver", +} + +var OptionMissingDomainResolver = Note{ + Name: "missing-domain-resolver", + Description: "missing `route.default_domain_resolver` or `domain_resolver` in dial fields", + DeprecatedVersion: "1.12.0", + ScheduledVersion: "1.14.0", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver", } var Options = []Note{ @@ -172,4 +190,8 @@ var Options = []Note{ OptionWireGuardOutbound, OptionWireGuardGSO, OptionTUNGSO, + OptionLegacyDNSTransport, + OptionLegacyDNSFakeIPOptions, + OptionOutboundDNSRuleItem, + OptionMissingDomainResolver, } diff --git a/option/dns.go b/option/dns.go index 8c9b8bda..f4418468 100644 --- a/option/dns.go +++ b/option/dns.go @@ -4,7 +4,6 @@ import ( "context" "net/netip" "net/url" - "os" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/experimental/deprecated" @@ -121,11 +120,6 @@ func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error { if o.Type != C.DNSTypeLegacy { return nil } - defer func() { - encoder := json.NewEncoder(os.Stderr) - encoder.SetIndent("", " ") - encoder.Encode(o) - }() options := o.Options.(*LegacyDNSServerOptions) serverURL, _ := url.Parse(options.Address) var serverType string @@ -139,18 +133,34 @@ func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error { serverType = C.DNSTypeUDP } } - remoteOptions := RemoteDNSServerOptions{ - LocalDNSServerOptions: LocalDNSServerOptions{ - DialerOptions: DialerOptions{ - Detour: options.Detour, + var remoteOptions RemoteDNSServerOptions + if options.Detour == "" { + remoteOptions = RemoteDNSServerOptions{ + LocalDNSServerOptions: LocalDNSServerOptions{ + LegacyStrategy: options.Strategy, + LegacyDefaultDialer: options.Detour == "", + LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}), }, - LegacyStrategy: options.Strategy, - LegacyDefaultDialer: options.Detour == "", - LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}), - }, - AddressResolver: options.AddressResolver, - AddressStrategy: options.AddressStrategy, - AddressFallbackDelay: options.AddressFallbackDelay, + LegacyAddressResolver: options.AddressResolver, + LegacyAddressStrategy: options.AddressStrategy, + LegacyAddressFallbackDelay: options.AddressFallbackDelay, + } + } else { + remoteOptions = RemoteDNSServerOptions{ + LocalDNSServerOptions: LocalDNSServerOptions{ + DialerOptions: DialerOptions{ + Detour: options.Detour, + DomainResolver: &DomainResolveOptions{ + Server: options.AddressResolver, + Strategy: options.AddressStrategy, + }, + FallbackDelay: options.AddressFallbackDelay, + }, + LegacyStrategy: options.Strategy, + LegacyDefaultDialer: options.Detour == "", + LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}), + }, + } } switch serverType { case C.DNSTypeLocal: @@ -291,9 +301,9 @@ type LocalDNSServerOptions struct { type RemoteDNSServerOptions struct { LocalDNSServerOptions ServerOptions - AddressResolver string `json:"address_resolver,omitempty"` - AddressStrategy DomainStrategy `json:"address_strategy,omitempty"` - AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"` + LegacyAddressResolver string `json:"-"` + LegacyAddressStrategy DomainStrategy `json:"-"` + LegacyAddressFallbackDelay badoption.Duration `json:"-"` } type RemoteTLSDNSServerOptions struct { diff --git a/option/outbound.go b/option/outbound.go index 5cadd3e2..99e3361a 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -77,12 +77,46 @@ type DialerOptions struct { TCPMultiPath bool `json:"tcp_multi_path,omitempty"` UDPFragment *bool `json:"udp_fragment,omitempty"` UDPFragmentDefault bool `json:"-"` - DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` + DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"` NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"` NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"` FallbackNetworkType badoption.Listable[InterfaceType] `json:"fallback_network_type,omitempty"` FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"` IsWireGuardListener bool `json:"-"` + + // Deprecated: migrated to domain resolver + DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` +} + +type _DomainResolveOptions struct { + Server string `json:"server"` + Strategy DomainStrategy `json:"strategy,omitempty"` + DisableCache bool `json:"disable_cache,omitempty"` + RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"` + ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` +} + +type DomainResolveOptions _DomainResolveOptions + +func (o DomainResolveOptions) MarshalJSON() ([]byte, error) { + if o.Strategy == DomainStrategy(C.DomainStrategyAsIS) && + !o.DisableCache && + o.RewriteTTL == nil && + o.ClientSubnet == nil { + return json.Marshal(o.Server) + } else { + return json.Marshal((_DomainResolveOptions)(o)) + } +} + +func (o *DomainResolveOptions) UnmarshalJSON(bytes []byte) error { + var stringValue string + err := json.Unmarshal(bytes, &stringValue) + if err == nil { + o.Server = stringValue + return nil + } + return json.Unmarshal(bytes, (*_DomainResolveOptions)(o)) } func (o *DialerOptions) TakeDialerOptions() DialerOptions { @@ -107,6 +141,10 @@ func (o ServerOptions) Build() M.Socksaddr { return M.ParseSocksaddrHostPort(o.Server, o.ServerPort) } +func (o ServerOptions) ServerIsDomain() bool { + return M.IsDomainName(o.Server) +} + func (o *ServerOptions) TakeServerOptions() ServerOptions { return *o } diff --git a/option/route.go b/option/route.go index 1eb2294b..f4b65391 100644 --- a/option/route.go +++ b/option/route.go @@ -13,6 +13,7 @@ type RouteOptions struct { OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"` DefaultInterface string `json:"default_interface,omitempty"` DefaultMark FwMark `json:"default_mark,omitempty"` + DefaultDomainResolver *DomainResolveOptions `json:"default_domain_resolver,omitempty"` DefaultNetworkStrategy *NetworkStrategy `json:"default_network_strategy,omitempty"` DefaultNetworkType badoption.Listable[InterfaceType] `json:"default_network_type,omitempty"` DefaultFallbackNetworkType badoption.Listable[InterfaceType] `json:"default_fallback_network_type,omitempty"` diff --git a/protocol/direct/outbound.go b/protocol/direct/outbound.go index d173ec53..9b454f58 100644 --- a/protocol/direct/outbound.go +++ b/protocol/direct/outbound.go @@ -42,16 +42,20 @@ type Outbound struct { func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) { options.UDPFragmentDefault = true - outboundDialer, err := dialer.NewDirect(ctx, options.DialerOptions) + if options.Detour != "" { + return nil, E.New("`detour` is not supported in direct context") + } + outboundDialer, err := dialer.New(ctx, options.DialerOptions, false) if err != nil { return nil, err } outbound := &Outbound{ - Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), - logger: logger, + Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), + logger: logger, + //nolint:staticcheck domainStrategy: C.DomainStrategy(options.DomainStrategy), fallbackDelay: time.Duration(options.FallbackDelay), - dialer: outboundDialer, + dialer: outboundDialer.(dialer.ParallelInterfaceDialer), // loopBack: newLoopBackDetector(router), } //nolint:staticcheck diff --git a/protocol/http/outbound.go b/protocol/http/outbound.go index c58f3071..0570dde5 100644 --- a/protocol/http/outbound.go +++ b/protocol/http/outbound.go @@ -30,7 +30,7 @@ type Outbound struct { } func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (adapter.Outbound, error) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/hysteria/outbound.go b/protocol/hysteria/outbound.go index e1d8716c..7746df13 100644 --- a/protocol/hysteria/outbound.go +++ b/protocol/hysteria/outbound.go @@ -47,7 +47,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/hysteria2/outbound.go b/protocol/hysteria2/outbound.go index 74e87b37..c805f07e 100644 --- a/protocol/hysteria2/outbound.go +++ b/protocol/hysteria2/outbound.go @@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL return nil, E.New("unknown obfs type: ", options.Obfs.Type) } } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/shadowsocks/outbound.go b/protocol/shadowsocks/outbound.go index 7e7277ef..875c9e69 100644 --- a/protocol/shadowsocks/outbound.go +++ b/protocol/shadowsocks/outbound.go @@ -44,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/shadowtls/inbound.go b/protocol/shadowtls/inbound.go index 5ae5656f..1db191d8 100644 --- a/protocol/shadowtls/inbound.go +++ b/protocol/shadowtls/inbound.go @@ -47,7 +47,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo if options.Version > 1 { handshakeForServerName = make(map[string]shadowtls.HandshakeConfig) for serverName, serverOptions := range options.HandshakeForServerName { - handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions) + handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions, serverOptions.ServerIsDomain()) if err != nil { return nil, err } @@ -57,7 +57,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo } } } - handshakeDialer, err := dialer.New(ctx, options.Handshake.DialerOptions) + handshakeDialer, err := dialer.New(ctx, options.Handshake.DialerOptions, options.Handshake.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/shadowtls/outbound.go b/protocol/shadowtls/outbound.go index 2b480729..0731b033 100644 --- a/protocol/shadowtls/outbound.go +++ b/protocol/shadowtls/outbound.go @@ -68,7 +68,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL tlsHandshakeFunc = shadowtls.DefaultTLSHandshakeFunc(options.Password, stdTLSConfig) } } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/socks/outbound.go b/protocol/socks/outbound.go index 323149e2..851412ff 100644 --- a/protocol/socks/outbound.go +++ b/protocol/socks/outbound.go @@ -46,7 +46,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/ssh/outbound.go b/protocol/ssh/outbound.go index eb9970b5..304ea389 100644 --- a/protocol/ssh/outbound.go +++ b/protocol/ssh/outbound.go @@ -49,7 +49,7 @@ type Outbound struct { } func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (adapter.Outbound, error) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/tor/outbound.go b/protocol/tor/outbound.go index 58824b53..9a0e2d65 100644 --- a/protocol/tor/outbound.go +++ b/protocol/tor/outbound.go @@ -75,7 +75,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL } startConf.TorrcFile = torrcFile } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, false) if err != nil { return nil, err } diff --git a/protocol/trojan/outbound.go b/protocol/trojan/outbound.go index 82889bc1..37a6933c 100644 --- a/protocol/trojan/outbound.go +++ b/protocol/trojan/outbound.go @@ -38,7 +38,7 @@ type Outbound struct { } func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanOutboundOptions) (adapter.Outbound, error) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/tuic/outbound.go b/protocol/tuic/outbound.go index 49b01f96..a31d4850 100644 --- a/protocol/tuic/outbound.go +++ b/protocol/tuic/outbound.go @@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL case "quic": tuicUDPStream = true } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/vless/outbound.go b/protocol/vless/outbound.go index 1d832a65..e0208be9 100644 --- a/protocol/vless/outbound.go +++ b/protocol/vless/outbound.go @@ -41,7 +41,7 @@ type Outbound struct { } func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (adapter.Outbound, error) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/vmess/outbound.go b/protocol/vmess/outbound.go index d41b30d9..be05990e 100644 --- a/protocol/vmess/outbound.go +++ b/protocol/vmess/outbound.go @@ -41,7 +41,7 @@ type Outbound struct { } func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (adapter.Outbound, error) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/wireguard/endpoint.go b/protocol/wireguard/endpoint.go index 300701a9..e167bec1 100644 --- a/protocol/wireguard/endpoint.go +++ b/protocol/wireguard/endpoint.go @@ -53,7 +53,14 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL if options.Detour == "" { options.IsWireGuardListener = true } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.DialerOptions, + RemoteIsDomain: common.Any(options.Peers, func(it option.WireGuardPeer) bool { + return !M.ParseAddr(it.Address).IsValid() + }), + ResolverOnDetour: true, + }) if err != nil { return nil, err } @@ -81,9 +88,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL PrivateKey: options.PrivateKey, ListenPort: options.ListenPort, ResolvePeer: func(domain string) (netip.Addr, error) { - endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{ - Strategy: C.DomainStrategy(options.DomainStrategy), - }) + endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, outboundDialer.(dialer.ResolveDialer).QueryOptions()) if lookupErr != nil { return netip.Addr{}, lookupErr } diff --git a/protocol/wireguard/outbound.go b/protocol/wireguard/outbound.go index 4aa49a8d..edd8184c 100644 --- a/protocol/wireguard/outbound.go +++ b/protocol/wireguard/outbound.go @@ -56,7 +56,14 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL } else if options.GSO { return nil, E.New("gso is conflict with detour") } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.DialerOptions, + RemoteIsDomain: options.ServerIsDomain() || common.Any(options.Peers, func(it option.LegacyWireGuardPeer) bool { + return it.ServerIsDomain() + }), + ResolverOnDetour: true, + }) if err != nil { return nil, err } @@ -94,9 +101,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL Address: options.LocalAddress, PrivateKey: options.PrivateKey, ResolvePeer: func(domain string) (netip.Addr, error) { - endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{ - Strategy: C.DomainStrategy(options.DomainStrategy), - }) + endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, outboundDialer.(dialer.ResolveDialer).QueryOptions()) if lookupErr != nil { return netip.Addr{}, lookupErr } diff --git a/route/network.go b/route/network.go index ab1be76c..a494ce09 100644 --- a/route/network.go +++ b/route/network.go @@ -4,6 +4,7 @@ import ( "context" "errors" "net" + "net/netip" "os" "runtime" "strings" @@ -55,13 +56,21 @@ type NetworkManager struct { } func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) { + defaultDomainResolver := common.PtrValueOrDefault(routeOptions.DefaultDomainResolver) nm := &NetworkManager{ logger: logger, interfaceFinder: control.NewDefaultInterfaceFinder(), autoDetectInterface: routeOptions.AutoDetectInterface, defaultOptions: adapter.NetworkOptions{ - BindInterface: routeOptions.DefaultInterface, - RoutingMark: uint32(routeOptions.DefaultMark), + BindInterface: routeOptions.DefaultInterface, + RoutingMark: uint32(routeOptions.DefaultMark), + DomainResolver: defaultDomainResolver.Server, + DomainResolveOptions: adapter.DNSQueryOptions{ + Strategy: C.DomainStrategy(defaultDomainResolver.Strategy), + DisableCache: defaultDomainResolver.DisableCache, + RewriteTTL: defaultDomainResolver.RewriteTTL, + ClientSubnet: defaultDomainResolver.ClientSubnet.Build(netip.Prefix{}), + }, NetworkStrategy: (*C.NetworkStrategy)(routeOptions.DefaultNetworkStrategy), NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build), FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build), diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index 7287ad86..88149aff 100644 --- a/route/rule/rule_action.go +++ b/route/rule/rule_action.go @@ -49,7 +49,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout), }, nil case C.RuleActionTypeDirect: - directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions)) + directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false) if err != nil { return nil, err } diff --git a/route/rule/rule_dns.go b/route/rule/rule_dns.go index 9d1c69b8..087fb7b2 100644 --- a/route/rule/rule_dns.go +++ b/route/rule/rule_dns.go @@ -210,7 +210,7 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op rule.allItems = append(rule.allItems, item) } if len(options.Outbound) > 0 { - item := NewOutboundRule(options.Outbound) + item := NewOutboundRule(ctx, options.Outbound) rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } diff --git a/route/rule/rule_item_outbound.go b/route/rule/rule_item_outbound.go index 3f37dee7..a13d0597 100644 --- a/route/rule/rule_item_outbound.go +++ b/route/rule/rule_item_outbound.go @@ -1,9 +1,11 @@ package rule import ( + "context" "strings" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/experimental/deprecated" F "github.com/sagernet/sing/common/format" ) @@ -15,7 +17,8 @@ type OutboundItem struct { matchAny bool } -func NewOutboundRule(outbounds []string) *OutboundItem { +func NewOutboundRule(ctx context.Context, outbounds []string) *OutboundItem { + deprecated.Report(ctx, deprecated.OptionOutboundDNSRuleItem) rule := &OutboundItem{outbounds: outbounds, outboundMap: make(map[string]bool)} for _, outbound := range outbounds { if outbound == "any" { @@ -28,8 +31,8 @@ func NewOutboundRule(outbounds []string) *OutboundItem { } func (r *OutboundItem) Match(metadata *adapter.InboundContext) bool { - if r.matchAny && metadata.Outbound != "" { - return true + if r.matchAny { + return metadata.Outbound != "" } return r.outboundMap[metadata.Outbound] } From a18c7d6eb926c833d039c56cc56e3209dddb25db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 26 Jan 2025 09:01:00 +0800 Subject: [PATCH 39/62] Add TLS fragment support --- adapter/inbound.go | 2 + common/process/searcher.go | 1 + common/process/searcher_windows.go | 199 ++--------------------------- common/tlsfragment/conn.go | 107 ++++++++++++++++ common/tlsfragment/index.go | 131 +++++++++++++++++++ common/tlsfragment/wait_darwin.go | 93 ++++++++++++++ common/tlsfragment/wait_linux.go | 40 ++++++ common/tlsfragment/wait_stub.go | 14 ++ common/tlsfragment/wait_windows.go | 28 ++++ constant/timeout.go | 1 + go.mod | 2 +- go.sum | 4 +- option/rule_action.go | 3 + route/conn.go | 16 +++ route/route.go | 4 + route/rule/rule_action.go | 12 ++ transport/simple-obfs/http.go | 4 + transport/simple-obfs/tls.go | 4 + 18 files changed, 476 insertions(+), 189 deletions(-) create mode 100644 common/tlsfragment/conn.go create mode 100644 common/tlsfragment/index.go create mode 100644 common/tlsfragment/wait_darwin.go create mode 100644 common/tlsfragment/wait_linux.go create mode 100644 common/tlsfragment/wait_stub.go create mode 100644 common/tlsfragment/wait_windows.go diff --git a/adapter/inbound.go b/adapter/inbound.go index f70066f5..bd7ec714 100644 --- a/adapter/inbound.go +++ b/adapter/inbound.go @@ -71,6 +71,8 @@ type InboundContext struct { UDPDisableDomainUnmapping bool UDPConnect bool UDPTimeout time.Duration + TLSFragment bool + TLSFragmentFallbackDelay time.Duration NetworkStrategy *C.NetworkStrategy NetworkType []C.InterfaceType diff --git a/common/process/searcher.go b/common/process/searcher.go index cee81068..d525b3c1 100644 --- a/common/process/searcher.go +++ b/common/process/searcher.go @@ -23,6 +23,7 @@ type Config struct { } type Info struct { + ProcessID uint32 ProcessPath string PackageName string User string diff --git a/common/process/searcher_windows.go b/common/process/searcher_windows.go index 5b3d59b5..b7d89dda 100644 --- a/common/process/searcher_windows.go +++ b/common/process/searcher_windows.go @@ -2,14 +2,11 @@ package process import ( "context" - "fmt" "net/netip" - "os" "syscall" - "unsafe" E "github.com/sagernet/sing/common/exceptions" - N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/winiphlpapi" "golang.org/x/sys/windows" ) @@ -26,209 +23,39 @@ func NewSearcher(_ Config) (Searcher, error) { return &windowsSearcher{}, nil } -var ( - modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") - procGetExtendedTcpTable = modiphlpapi.NewProc("GetExtendedTcpTable") - procGetExtendedUdpTable = modiphlpapi.NewProc("GetExtendedUdpTable") - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW") -) - func initWin32API() error { - err := modiphlpapi.Load() - if err != nil { - return E.Cause(err, "load iphlpapi.dll") - } - - err = procGetExtendedTcpTable.Find() - if err != nil { - return E.Cause(err, "load iphlpapi::GetExtendedTcpTable") - } - - err = procGetExtendedUdpTable.Find() - if err != nil { - return E.Cause(err, "load iphlpapi::GetExtendedUdpTable") - } - - err = modkernel32.Load() - if err != nil { - return E.Cause(err, "load kernel32.dll") - } - - err = procQueryFullProcessImageNameW.Find() - if err != nil { - return E.Cause(err, "load kernel32::QueryFullProcessImageNameW") - } - - return nil + return winiphlpapi.LoadExtendedTable() } func (s *windowsSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { - processName, err := findProcessName(network, source.Addr(), int(source.Port())) + pid, err := winiphlpapi.FindPid(network, source) if err != nil { return nil, err } - return &Info{ProcessPath: processName, UserId: -1}, nil -} - -func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) { - family := windows.AF_INET - if ip.Is6() { - family = windows.AF_INET6 - } - - const ( - tcpTablePidConn = 4 - udpTablePid = 1 - ) - - var class int - var fn uintptr - switch network { - case N.NetworkTCP: - fn = procGetExtendedTcpTable.Addr() - class = tcpTablePidConn - case N.NetworkUDP: - fn = procGetExtendedUdpTable.Addr() - class = udpTablePid - default: - return "", os.ErrInvalid - } - - buf, err := getTransportTable(fn, family, class) + path, err := getProcessPath(pid) if err != nil { - return "", err + return &Info{ProcessID: pid, UserId: -1}, err } - - s := newSearcher(family == windows.AF_INET, network == N.NetworkTCP) - - pid, err := s.Search(buf, ip, uint16(srcPort)) - if err != nil { - return "", err - } - return getExecPathFromPID(pid) + return &Info{ProcessID: pid, ProcessPath: path, UserId: -1}, nil } -type searcher struct { - itemSize int - port int - ip int - ipSize int - pid int - tcpState int -} - -func (s *searcher) Search(b []byte, ip netip.Addr, port uint16) (uint32, error) { - n := int(readNativeUint32(b[:4])) - itemSize := s.itemSize - for i := 0; i < n; i++ { - row := b[4+itemSize*i : 4+itemSize*(i+1)] - - if s.tcpState >= 0 { - tcpState := readNativeUint32(row[s.tcpState : s.tcpState+4]) - // MIB_TCP_STATE_ESTAB, only check established connections for TCP - if tcpState != 5 { - continue - } - } - - // according to MSDN, only the lower 16 bits of dwLocalPort are used and the port number is in network endian. - // this field can be illustrated as follows depends on different machine endianess: - // little endian: [ MSB LSB 0 0 ] interpret as native uint32 is ((LSB<<8)|MSB) - // big endian: [ 0 0 MSB LSB ] interpret as native uint32 is ((MSB<<8)|LSB) - // so we need an syscall.Ntohs on the lower 16 bits after read the port as native uint32 - srcPort := syscall.Ntohs(uint16(readNativeUint32(row[s.port : s.port+4]))) - if srcPort != port { - continue - } - - srcIP, _ := netip.AddrFromSlice(row[s.ip : s.ip+s.ipSize]) - // windows binds an unbound udp socket to 0.0.0.0/[::] while first sendto - if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) { - continue - } - - pid := readNativeUint32(row[s.pid : s.pid+4]) - return pid, nil - } - return 0, ErrNotFound -} - -func newSearcher(isV4, isTCP bool) *searcher { - var itemSize, port, ip, ipSize, pid int - tcpState := -1 - switch { - case isV4 && isTCP: - // struct MIB_TCPROW_OWNER_PID - itemSize, port, ip, ipSize, pid, tcpState = 24, 8, 4, 4, 20, 0 - case isV4 && !isTCP: - // struct MIB_UDPROW_OWNER_PID - itemSize, port, ip, ipSize, pid = 12, 4, 0, 4, 8 - case !isV4 && isTCP: - // struct MIB_TCP6ROW_OWNER_PID - itemSize, port, ip, ipSize, pid, tcpState = 56, 20, 0, 16, 52, 48 - case !isV4 && !isTCP: - // struct MIB_UDP6ROW_OWNER_PID - itemSize, port, ip, ipSize, pid = 28, 20, 0, 16, 24 - } - - return &searcher{ - itemSize: itemSize, - port: port, - ip: ip, - ipSize: ipSize, - pid: pid, - tcpState: tcpState, - } -} - -func getTransportTable(fn uintptr, family int, class int) ([]byte, error) { - for size, buf := uint32(8), make([]byte, 8); ; { - ptr := unsafe.Pointer(&buf[0]) - err, _, _ := syscall.SyscallN(fn, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0) - - switch err { - case 0: - return buf, nil - case uintptr(syscall.ERROR_INSUFFICIENT_BUFFER): - buf = make([]byte, size) - default: - return nil, fmt.Errorf("syscall error: %d", err) - } - } -} - -func readNativeUint32(b []byte) uint32 { - return *(*uint32)(unsafe.Pointer(&b[0])) -} - -func getExecPathFromPID(pid uint32) (string, error) { - // kernel process starts with a colon in order to distinguish with normal processes +func getProcessPath(pid uint32) (string, error) { switch pid { case 0: - // reserved pid for system idle process return ":System Idle Process", nil case 4: - // reserved pid for windows kernel image return ":System", nil } - h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid) + handle, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid) if err != nil { return "", err } - defer windows.CloseHandle(h) - + defer windows.CloseHandle(handle) + size := uint32(syscall.MAX_LONG_PATH) buf := make([]uint16, syscall.MAX_LONG_PATH) - size := uint32(len(buf)) - r1, _, err := syscall.SyscallN( - procQueryFullProcessImageNameW.Addr(), - uintptr(h), - uintptr(0), - uintptr(unsafe.Pointer(&buf[0])), - uintptr(unsafe.Pointer(&size)), - ) - if r1 == 0 { + err = windows.QueryFullProcessImageName(handle, 0, &buf[0], &size) + if err != nil { return "", err } - return syscall.UTF16ToString(buf[:size]), nil + return windows.UTF16ToString(buf[:size]), nil } diff --git a/common/tlsfragment/conn.go b/common/tlsfragment/conn.go new file mode 100644 index 00000000..6f2a3dad --- /dev/null +++ b/common/tlsfragment/conn.go @@ -0,0 +1,107 @@ +package tf + +import ( + "context" + "math/rand" + "net" + "strings" + "time" + + N "github.com/sagernet/sing/common/network" + + "golang.org/x/net/publicsuffix" +) + +type Conn struct { + net.Conn + tcpConn *net.TCPConn + ctx context.Context + firstPacketWritten bool + fallbackDelay time.Duration +} + +func NewConn(conn net.Conn, ctx context.Context, fallbackDelay time.Duration) (*Conn, error) { + tcpConn, _ := N.UnwrapReader(conn).(*net.TCPConn) + return &Conn{ + Conn: conn, + tcpConn: tcpConn, + ctx: ctx, + fallbackDelay: fallbackDelay, + }, nil +} + +func (c *Conn) Write(b []byte) (n int, err error) { + if !c.firstPacketWritten { + defer func() { + c.firstPacketWritten = true + }() + serverName := indexTLSServerName(b) + if serverName != nil { + if c.tcpConn != nil { + err = c.tcpConn.SetNoDelay(true) + if err != nil { + return + } + } + splits := strings.Split(serverName.ServerName, ".") + currentIndex := serverName.Index + if publicSuffix := publicsuffix.List.PublicSuffix(serverName.ServerName); publicSuffix != "" { + splits = splits[:len(splits)-strings.Count(serverName.ServerName, ".")] + } + if len(splits) > 1 && splits[0] == "..." { + currentIndex += len(splits[0]) + 1 + splits = splits[1:] + } + var splitIndexes []int + for i, split := range splits { + splitAt := rand.Intn(len(split)) + splitIndexes = append(splitIndexes, currentIndex+splitAt) + currentIndex += len(split) + if i != len(splits)-1 { + currentIndex++ + } + } + for i := 0; i <= len(splitIndexes); i++ { + var payload []byte + if i == 0 { + payload = b[:splitIndexes[i]] + } else if i == len(splitIndexes) { + payload = b[splitIndexes[i-1]:] + } else { + payload = b[splitIndexes[i-1]:splitIndexes[i]] + } + if c.tcpConn != nil && i != len(splitIndexes) { + err = writeAndWaitAck(c.ctx, c.tcpConn, payload, c.fallbackDelay) + if err != nil { + return + } + } else { + _, err = c.Conn.Write(payload) + if err != nil { + return + } + } + } + if c.tcpConn != nil { + err = c.tcpConn.SetNoDelay(false) + if err != nil { + return + } + } + return len(b), nil + } + } + return c.Conn.Write(b) +} + +func (c *Conn) ReaderReplaceable() bool { + return true +} + +func (c *Conn) WriterReplaceable() bool { + return c.firstPacketWritten +} + +func (c *Conn) Upstream() any { + return c.Conn +} diff --git a/common/tlsfragment/index.go b/common/tlsfragment/index.go new file mode 100644 index 00000000..59031cec --- /dev/null +++ b/common/tlsfragment/index.go @@ -0,0 +1,131 @@ +package tf + +import ( + "encoding/binary" +) + +const ( + recordLayerHeaderLen int = 5 + handshakeHeaderLen int = 6 + randomDataLen int = 32 + sessionIDHeaderLen int = 1 + cipherSuiteHeaderLen int = 2 + compressMethodHeaderLen int = 1 + extensionsHeaderLen int = 2 + extensionHeaderLen int = 4 + sniExtensionHeaderLen int = 5 + contentType uint8 = 22 + handshakeType uint8 = 1 + sniExtensionType uint16 = 0 + sniNameDNSHostnameType uint8 = 0 + tlsVersionBitmask uint16 = 0xFFFC + tls13 uint16 = 0x0304 +) + +type myServerName struct { + Index int + Length int + ServerName string +} + +func indexTLSServerName(payload []byte) *myServerName { + if len(payload) < recordLayerHeaderLen || payload[0] != contentType { + return nil + } + segmentLen := binary.BigEndian.Uint16(payload[3:5]) + if len(payload) < recordLayerHeaderLen+int(segmentLen) { + return nil + } + serverName := indexTLSServerNameFromHandshake(payload[recordLayerHeaderLen : recordLayerHeaderLen+int(segmentLen)]) + if serverName == nil { + return nil + } + serverName.Length += recordLayerHeaderLen + return serverName +} + +func indexTLSServerNameFromHandshake(hs []byte) *myServerName { + if len(hs) < handshakeHeaderLen+randomDataLen+sessionIDHeaderLen { + return nil + } + if hs[0] != handshakeType { + return nil + } + handshakeLen := uint32(hs[1])<<16 | uint32(hs[2])<<8 | uint32(hs[3]) + if len(hs[4:]) != int(handshakeLen) { + return nil + } + tlsVersion := uint16(hs[4])<<8 | uint16(hs[5]) + if tlsVersion&tlsVersionBitmask != 0x0300 && tlsVersion != tls13 { + return nil + } + sessionIDLen := hs[38] + if len(hs) < handshakeHeaderLen+randomDataLen+sessionIDHeaderLen+int(sessionIDLen) { + return nil + } + cs := hs[handshakeHeaderLen+randomDataLen+sessionIDHeaderLen+int(sessionIDLen):] + if len(cs) < cipherSuiteHeaderLen { + return nil + } + csLen := uint16(cs[0])<<8 | uint16(cs[1]) + if len(cs) < cipherSuiteHeaderLen+int(csLen)+compressMethodHeaderLen { + return nil + } + compressMethodLen := uint16(cs[cipherSuiteHeaderLen+int(csLen)]) + if len(cs) < cipherSuiteHeaderLen+int(csLen)+compressMethodHeaderLen+int(compressMethodLen) { + return nil + } + currentIndex := cipherSuiteHeaderLen + int(csLen) + compressMethodHeaderLen + int(compressMethodLen) + serverName := indexTLSServerNameFromExtensions(cs[currentIndex:]) + if serverName == nil { + return nil + } + serverName.Index += currentIndex + return serverName +} + +func indexTLSServerNameFromExtensions(exs []byte) *myServerName { + if len(exs) == 0 { + return nil + } + if len(exs) < extensionsHeaderLen { + return nil + } + exsLen := uint16(exs[0])<<8 | uint16(exs[1]) + exs = exs[extensionsHeaderLen:] + if len(exs) < int(exsLen) { + return nil + } + for currentIndex := extensionsHeaderLen; len(exs) > 0; { + if len(exs) < extensionHeaderLen { + return nil + } + exType := uint16(exs[0])<<8 | uint16(exs[1]) + exLen := uint16(exs[2])<<8 | uint16(exs[3]) + if len(exs) < extensionHeaderLen+int(exLen) { + return nil + } + sex := exs[extensionHeaderLen : extensionHeaderLen+int(exLen)] + + switch exType { + case sniExtensionType: + if len(sex) < sniExtensionHeaderLen { + return nil + } + sniType := sex[2] + if sniType != sniNameDNSHostnameType { + return nil + } + sniLen := uint16(sex[3])<<8 | uint16(sex[4]) + sex = sex[sniExtensionHeaderLen:] + return &myServerName{ + Index: currentIndex + extensionHeaderLen + sniExtensionHeaderLen, + Length: int(sniLen), + ServerName: string(sex), + } + } + exs = exs[4+exLen:] + currentIndex += 4 + int(exLen) + } + return nil +} diff --git a/common/tlsfragment/wait_darwin.go b/common/tlsfragment/wait_darwin.go new file mode 100644 index 00000000..90c65ba2 --- /dev/null +++ b/common/tlsfragment/wait_darwin.go @@ -0,0 +1,93 @@ +package tf + +import ( + "context" + "net" + "time" + + "github.com/sagernet/sing/common/control" + + "golang.org/x/sys/unix" +) + +/* +const tcpMaxNotifyAck = 10 + +type tcpNotifyAckID uint32 + + type tcpNotifyAckComplete struct { + NotifyPending uint32 + NotifyCompleteCount uint32 + NotifyCompleteID [tcpMaxNotifyAck]tcpNotifyAckID + } + +var sizeOfTCPNotifyAckComplete = int(unsafe.Sizeof(tcpNotifyAckComplete{})) + + func getsockoptTCPNotifyAckComplete(fd, level, opt int) (*tcpNotifyAckComplete, error) { + var value tcpNotifyAckComplete + vallen := uint32(sizeOfTCPNotifyAckComplete) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err + } + +//go:linkname getsockopt golang.org/x/sys/unix.getsockopt +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *uint32) error + + func waitAck(ctx context.Context, conn *net.TCPConn, _ time.Duration) error { + const TCP_NOTIFY_ACKNOWLEDGEMENT = 0x212 + return control.Conn(conn, func(fd uintptr) error { + err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, TCP_NOTIFY_ACKNOWLEDGEMENT, 1) + if err != nil { + if errors.Is(err, unix.EINVAL) { + return waitAckFallback(ctx, conn, 0) + } + return err + } + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + var ackComplete *tcpNotifyAckComplete + ackComplete, err = getsockoptTCPNotifyAckComplete(int(fd), unix.IPPROTO_TCP, TCP_NOTIFY_ACKNOWLEDGEMENT) + if err != nil { + return err + } + if ackComplete.NotifyPending == 0 { + return nil + } + time.Sleep(10 * time.Millisecond) + } + }) + } +*/ + +func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error { + _, err := conn.Write(payload) + if err != nil { + return err + } + return control.Conn(conn, func(fd uintptr) error { + start := time.Now() + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + unacked, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_NWRITE) + if err != nil { + return err + } + if unacked == 0 { + if time.Since(start) <= 20*time.Millisecond { + // under transparent proxy + time.Sleep(fallbackDelay) + } + return nil + } + time.Sleep(10 * time.Millisecond) + } + }) +} diff --git a/common/tlsfragment/wait_linux.go b/common/tlsfragment/wait_linux.go new file mode 100644 index 00000000..517d6ea5 --- /dev/null +++ b/common/tlsfragment/wait_linux.go @@ -0,0 +1,40 @@ +package tf + +import ( + "context" + "net" + "time" + + "github.com/sagernet/sing/common/control" + + "golang.org/x/sys/unix" +) + +func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error { + _, err := conn.Write(payload) + if err != nil { + return err + } + return control.Conn(conn, func(fd uintptr) error { + start := time.Now() + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + tcpInfo, err := unix.GetsockoptTCPInfo(int(fd), unix.IPPROTO_TCP, unix.TCP_INFO) + if err != nil { + return err + } + if tcpInfo.Unacked == 0 { + if time.Since(start) <= 20*time.Millisecond { + // under transparent proxy + time.Sleep(fallbackDelay) + } + return nil + } + time.Sleep(10 * time.Millisecond) + } + }) +} diff --git a/common/tlsfragment/wait_stub.go b/common/tlsfragment/wait_stub.go new file mode 100644 index 00000000..7e451a04 --- /dev/null +++ b/common/tlsfragment/wait_stub.go @@ -0,0 +1,14 @@ +//go:build !(linux || darwin || windows) + +package tf + +import ( + "context" + "net" + "time" +) + +func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error { + time.Sleep(fallbackDelay) + return nil +} diff --git a/common/tlsfragment/wait_windows.go b/common/tlsfragment/wait_windows.go new file mode 100644 index 00000000..118a204d --- /dev/null +++ b/common/tlsfragment/wait_windows.go @@ -0,0 +1,28 @@ +package tf + +import ( + "context" + "errors" + "net" + "time" + + "github.com/sagernet/sing/common/winiphlpapi" + + "golang.org/x/sys/windows" +) + +func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error { + start := time.Now() + err := winiphlpapi.WriteAndWaitAck(ctx, conn, payload) + if err != nil { + if errors.Is(err, windows.ERROR_ACCESS_DENIED) { + time.Sleep(fallbackDelay) + return nil + } + return err + } + if time.Since(start) <= 20*time.Millisecond { + time.Sleep(fallbackDelay) + } + return nil +} diff --git a/constant/timeout.go b/constant/timeout.go index 3b5a452b..eb0fd34c 100644 --- a/constant/timeout.go +++ b/constant/timeout.go @@ -16,6 +16,7 @@ const ( StopTimeout = 5 * time.Second FatalStopTimeout = 10 * time.Second FakeIPMetadataSaveInterval = 10 * time.Second + TLSFragmentFallbackDelay = 500 * time.Millisecond ) var PortProtocols = map[uint16]string{ diff --git a/go.mod b/go.mod index 31af0eb8..28f84a54 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.6.1 + github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff github.com/sagernet/sing-mux v0.3.1 github.com/sagernet/sing-quic v0.4.0 github.com/sagernet/sing-shadowsocks v0.2.7 diff --git a/go.sum b/go.sum index 0f4ce794..5b5b168d 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA= -github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff h1:5UGghwx8cI14qFa0ienrLekAYfhdKAiWvJUkY7rHmsI= +github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78= github.com/sagernet/sing-quic v0.4.0 h1:E4geazHk/UrJTXMlT+CBCKmn8V86RhtNeczWtfeoEFc= diff --git a/option/rule_action.go b/option/rule_action.go index a715d260..f07d7298 100644 --- a/option/rule_action.go +++ b/option/rule_action.go @@ -150,6 +150,9 @@ type RawRouteOptionsActionOptions struct { UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"` UDPConnect bool `json:"udp_connect,omitempty"` UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"` + + TLSFragment bool `json:"tls_fragment,omitempty"` + TLSFragmentFallbackDelay badoption.Duration `json:"tls_fragment_fallback_delay,omitempty"` } type RouteOptionsActionOptions RawRouteOptionsActionOptions diff --git a/route/conn.go b/route/conn.go index 1c0d3c90..acb973f9 100644 --- a/route/conn.go +++ b/route/conn.go @@ -11,6 +11,7 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/tlsfragment" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" @@ -75,6 +76,21 @@ func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, co m.logger.ErrorContext(ctx, err) return } + if metadata.TLSFragment { + fallbackDelay := metadata.TLSFragmentFallbackDelay + if fallbackDelay == 0 { + fallbackDelay = C.TLSFragmentFallbackDelay + } + var newConn *tf.Conn + newConn, err = tf.NewConn(remoteConn, ctx, fallbackDelay) + if err != nil { + conn.Close() + remoteConn.Close() + m.logger.ErrorContext(ctx, err) + return + } + remoteConn = newConn + } m.access.Lock() element := m.connections.PushBack(conn) m.access.Unlock() diff --git a/route/route.go b/route/route.go index 248afe7d..2b15d650 100644 --- a/route/route.go +++ b/route/route.go @@ -454,6 +454,10 @@ match: if routeOptions.UDPTimeout > 0 { metadata.UDPTimeout = routeOptions.UDPTimeout } + if routeOptions.TLSFragment { + metadata.TLSFragment = true + metadata.TLSFragmentFallbackDelay = routeOptions.TLSFragmentFallbackDelay + } } switch action := currentRule.Action().(type) { case *rule.RuleActionSniff: diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index 88149aff..96515dad 100644 --- a/route/rule/rule_action.go +++ b/route/rule/rule_action.go @@ -36,6 +36,8 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti FallbackDelay: time.Duration(action.RouteOptions.FallbackDelay), UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping, UDPConnect: action.RouteOptions.UDPConnect, + TLSFragment: action.RouteOptions.TLSFragment, + TLSFragmentFallbackDelay: time.Duration(action.RouteOptions.TLSFragmentFallbackDelay), }, }, nil case C.RuleActionTypeRouteOptions: @@ -47,6 +49,8 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti UDPDisableDomainUnmapping: action.RouteOptionsOptions.UDPDisableDomainUnmapping, UDPConnect: action.RouteOptionsOptions.UDPConnect, UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout), + TLSFragment: action.RouteOptionsOptions.TLSFragment, + TLSFragmentFallbackDelay: time.Duration(action.RouteOptionsOptions.TLSFragmentFallbackDelay), }, nil case C.RuleActionTypeDirect: directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false) @@ -142,6 +146,9 @@ func (r *RuleActionRoute) String() string { if r.UDPConnect { descriptions = append(descriptions, "udp-connect") } + if r.TLSFragment { + descriptions = append(descriptions, "tls-fragment") + } return F.ToString("route(", strings.Join(descriptions, ","), ")") } @@ -155,6 +162,8 @@ type RuleActionRouteOptions struct { UDPDisableDomainUnmapping bool UDPConnect bool UDPTimeout time.Duration + TLSFragment bool + TLSFragmentFallbackDelay time.Duration } func (r *RuleActionRouteOptions) Type() string { @@ -187,6 +196,9 @@ func (r *RuleActionRouteOptions) String() string { if r.UDPConnect { descriptions = append(descriptions, "udp-connect") } + if r.UDPTimeout > 0 { + descriptions = append(descriptions, "udp-timeout") + } return F.ToString("route-options(", strings.Join(descriptions, ","), ")") } diff --git a/transport/simple-obfs/http.go b/transport/simple-obfs/http.go index f77a63a8..df38768e 100644 --- a/transport/simple-obfs/http.go +++ b/transport/simple-obfs/http.go @@ -82,6 +82,10 @@ func (ho *HTTPObfs) Write(b []byte) (int, error) { return ho.Conn.Write(b) } +func (ho *HTTPObfs) Upstream() any { + return ho.Conn +} + // NewHTTPObfs return a HTTPObfs func NewHTTPObfs(conn net.Conn, host string, port string) net.Conn { return &HTTPObfs{ diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go index 51756fdb..96564815 100644 --- a/transport/simple-obfs/tls.go +++ b/transport/simple-obfs/tls.go @@ -113,6 +113,10 @@ func (to *TLSObfs) write(b []byte) (int, error) { return len(b), err } +func (to *TLSObfs) Upstream() any { + return to.Conn +} + // NewTLSObfs return a SimpleObfs func NewTLSObfs(conn net.Conn, server string) net.Conn { return &TLSObfs{ From 128325b128fab0c1a45421d90d3d9cc226e4690a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 8 Jan 2025 10:34:45 +0800 Subject: [PATCH 40/62] Add certificate store --- Makefile | 3 + adapter/certificate.go | 21 + adapter/experimental.go | 16 +- adapter/router.go | 10 +- box.go | 16 +- cmd/internal/update_certificates/main.go | 68 + common/certificate/mozilla.go | 4359 +++++++++++++++++++++ common/certificate/store.go | 185 + common/tls/ech_client.go | 1 + common/tls/ech_server.go | 2 +- common/tls/reality_client.go | 14 +- common/tls/std_client.go | 2 + common/tls/std_server.go | 2 +- common/tls/utls_client.go | 2 + common/urltest/urltest.go | 20 +- constant/certificate.go | 7 + experimental/clashapi/api_meta_group.go | 2 +- experimental/clashapi/proxies.go | 8 +- experimental/clashapi/server.go | 6 +- experimental/clashapi/server_resources.go | 6 + experimental/libbox/command_urltest.go | 2 +- experimental/libbox/config.go | 4 + experimental/libbox/platform.go | 1 + experimental/libbox/platform/interface.go | 1 + experimental/libbox/service.go | 6 +- option/certificate.go | 36 + option/options.go | 1 + protocol/group/urltest.go | 9 +- route/router.go | 2 +- route/rule/rule_set_remote.go | 6 + 30 files changed, 4786 insertions(+), 32 deletions(-) create mode 100644 adapter/certificate.go create mode 100644 cmd/internal/update_certificates/main.go create mode 100644 common/certificate/mozilla.go create mode 100644 common/certificate/store.go create mode 100644 constant/certificate.go create mode 100644 option/certificate.go diff --git a/Makefile b/Makefile index 46123327..663ae922 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,9 @@ proto_install: go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest +update_certificates: + go run ./cmd/internal/update_certificates + release: go run ./cmd/internal/build goreleaser release --clean --skip publish mkdir dist/release diff --git a/adapter/certificate.go b/adapter/certificate.go new file mode 100644 index 00000000..0998e130 --- /dev/null +++ b/adapter/certificate.go @@ -0,0 +1,21 @@ +package adapter + +import ( + "context" + "crypto/x509" + + "github.com/sagernet/sing/service" +) + +type CertificateStore interface { + LifecycleService + Pool() *x509.CertPool +} + +func RootPoolFromContext(ctx context.Context) *x509.CertPool { + store := service.FromContext[CertificateStore](ctx) + if store == nil { + return nil + } + return store.Pool() +} diff --git a/adapter/experimental.go b/adapter/experimental.go index 99d7c9a5..de01d7be 100644 --- a/adapter/experimental.go +++ b/adapter/experimental.go @@ -6,7 +6,6 @@ import ( "encoding/binary" "time" - "github.com/sagernet/sing-box/common/urltest" "github.com/sagernet/sing/common/varbin" ) @@ -15,7 +14,20 @@ type ClashServer interface { ConnectionTracker Mode() string ModeList() []string - HistoryStorage() *urltest.HistoryStorage + HistoryStorage() URLTestHistoryStorage +} + +type URLTestHistory struct { + Time time.Time `json:"time"` + Delay uint16 `json:"delay"` +} + +type URLTestHistoryStorage interface { + SetHook(hook chan<- struct{}) + LoadURLTestHistory(tag string) *URLTestHistory + DeleteURLTestHistory(tag string) + StoreURLTestHistory(tag string, history *URLTestHistory) + Close() error } type V2RayServer interface { diff --git a/adapter/router.go b/adapter/router.go index 9cefb49d..b82cb5d8 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -2,6 +2,7 @@ package adapter import ( "context" + "crypto/tls" "net" "net/http" "sync" @@ -9,6 +10,7 @@ import ( C "github.com/sagernet/sing-box/constant" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/ntp" "github.com/sagernet/sing/common/x/list" "go4.org/netipx" @@ -66,12 +68,14 @@ type RuleSetMetadata struct { ContainsIPCIDRRule bool } type HTTPStartContext struct { + ctx context.Context access sync.Mutex httpClientCache map[string]*http.Client } -func NewHTTPStartContext() *HTTPStartContext { +func NewHTTPStartContext(ctx context.Context) *HTTPStartContext { return &HTTPStartContext{ + ctx: ctx, httpClientCache: make(map[string]*http.Client), } } @@ -89,6 +93,10 @@ func (c *HTTPStartContext) HTTPClient(detour string, dialer N.Dialer) *http.Clie DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) }, + TLSClientConfig: &tls.Config{ + Time: ntp.TimeFuncFromContext(c.ctx), + RootCAs: RootPoolFromContext(c.ctx), + }, }, } c.httpClientCache[detour] = httpClient diff --git a/box.go b/box.go index 72ba43f8..08a4fd0b 100644 --- a/box.go +++ b/box.go @@ -12,6 +12,7 @@ import ( "github.com/sagernet/sing-box/adapter/endpoint" "github.com/sagernet/sing-box/adapter/inbound" "github.com/sagernet/sing-box/adapter/outbound" + "github.com/sagernet/sing-box/common/certificate" "github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/taskmonitor" "github.com/sagernet/sing-box/common/tls" @@ -141,6 +142,20 @@ func New(options Options) (*Box, error) { return nil, E.Cause(err, "create log factory") } + var services []adapter.LifecycleService + certificateOptions := common.PtrValueOrDefault(options.Certificate) + if C.IsAndroid || certificateOptions.Store != "" && certificateOptions.Store != C.CertificateStoreSystem || + len(certificateOptions.Certificate) > 0 || + len(certificateOptions.CertificatePath) > 0 || + len(certificateOptions.CertificateDirectoryPath) > 0 { + certificateStore, err := certificate.NewStore(ctx, logFactory.NewLogger("certificate"), certificateOptions) + if err != nil { + return nil, err + } + service.MustRegister[adapter.CertificateStore](ctx, certificateStore) + services = append(services, certificateStore) + } + routeOptions := common.PtrValueOrDefault(options.Route) dnsOptions := common.PtrValueOrDefault(options.DNS) endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry) @@ -280,7 +295,6 @@ func New(options Options) (*Box, error) { return nil, E.Cause(err, "initialize platform interface") } } - var services []adapter.LifecycleService if needCacheFile { cacheFile := cachefile.New(ctx, common.PtrValueOrDefault(experimentalOptions.CacheFile)) service.MustRegister[adapter.CacheFile](ctx, cacheFile) diff --git a/cmd/internal/update_certificates/main.go b/cmd/internal/update_certificates/main.go new file mode 100644 index 00000000..cf597c86 --- /dev/null +++ b/cmd/internal/update_certificates/main.go @@ -0,0 +1,68 @@ +package main + +import ( + "encoding/csv" + "io" + "net/http" + "os" + "strings" + + "github.com/sagernet/sing-box/log" + + "golang.org/x/exp/slices" +) + +func main() { + err := updateMozillaIncludedRootCAs() + if err != nil { + log.Error(err) + } +} + +func updateMozillaIncludedRootCAs() error { + response, err := http.Get("https://ccadb.my.salesforce-sites.com/mozilla/IncludedCACertificateReportPEMCSV") + if err != nil { + return err + } + defer response.Body.Close() + reader := csv.NewReader(response.Body) + header, err := reader.Read() + if err != nil { + return err + } + geoIndex := slices.Index(header, "Geographic Focus") + nameIndex := slices.Index(header, "Common Name or Certificate Name") + certIndex := slices.Index(header, "PEM Info") + + generated := strings.Builder{} + generated.WriteString(`// Code generated by 'make update_certificates'. DO NOT EDIT. + +package certificate + +import "crypto/x509" + +var mozillaIncluded *x509.CertPool + +func init() { + mozillaIncluded = x509.NewCertPool() +`) + for { + record, err := reader.Read() + if err == io.EOF { + break + } else if err != nil { + return err + } + if record[geoIndex] == "China" { + continue + } + generated.WriteString("\n // ") + generated.WriteString(record[nameIndex]) + generated.WriteString("\n") + generated.WriteString(" mozillaIncluded.AppendCertsFromPEM([]byte(`") + generated.WriteString(record[certIndex]) + generated.WriteString("`))\n") + } + generated.WriteString("}\n") + return os.WriteFile("common/certificate/mozilla.go", []byte(generated.String()), 0o644) +} diff --git a/common/certificate/mozilla.go b/common/certificate/mozilla.go new file mode 100644 index 00000000..3bf1d175 --- /dev/null +++ b/common/certificate/mozilla.go @@ -0,0 +1,4359 @@ +// Code generated by 'make update_certificates'. DO NOT EDIT. + +package certificate + +import "crypto/x509" + +var mozillaIncluded *x509.CertPool + +func init() { + mozillaIncluded = x509.NewCertPool() + + // Actalis Authentication Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE-----'`)) + + // TunTrust Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE-----'`)) + + // Amazon Root CA 1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE-----'`)) + + // Amazon Root CA 2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE-----'`)) + + // Amazon Root CA 3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE-----'`)) + + // Amazon Root CA 4 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE-----'`)) + + // Starfield Services Root Certificate Authority - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE-----'`)) + + // Certum CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E +jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo +ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI +ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu +Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg +AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 +HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA +uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa +TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg +xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q +CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x +O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs +6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE-----'`)) + + // Certum EC-384 CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE-----'`)) + + // Certum Trusted Network CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE-----'`)) + + // Certum Trusted Network CA 2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE-----'`)) + + // Certum Trusted Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 +MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu +MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV +BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw +MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg +U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ +n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q +p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq +NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF +8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 +HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa +mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi +7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF +ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P +qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ +v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 +Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD +ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 +WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo +zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR +5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ +GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf +5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq +0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D +P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM +qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP +0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf +E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE-----'`)) + + // Autoridad de Certificacion Firmaprofesional CIF A62634068 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE-----'`)) + + // FIRMAPROFESIONAL CA ROOT-A WEB + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw +CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE +YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB +IFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2WhcNNDcwMzMxMDkwMTM2WjBuMQsw +CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE +YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB +IFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zf +e9MEkVz6iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6C +cyvHZpsKjECcfIr28jlgst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FDY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0O +BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO +PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw +hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG +XSaQpYXFuXqUPoeovQA= +-----END CERTIFICATE-----'`)) + + // ANF Secure Server Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV +BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk +YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV +BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN +MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF +UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD +VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v +dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj +cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q +yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH +2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX +H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL +zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR +p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz +W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ +SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn +LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 +n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B +u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC +AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L +9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej +rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK +pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 +vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq +OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ +/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 +2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI ++PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 +MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo +tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE-----'`)) + + // Buypass Class 2 Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE-----'`)) + + // Buypass Class 3 Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE-----'`)) + + // Certainly Root E1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE-----'`)) + + // Certainly Root R1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE-----'`)) + + // Certigna + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE-----'`)) + + // Certigna Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE-----'`)) + + // certSIGN ROOT CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE-----'`)) + + // certSIGN ROOT CA G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE-----'`)) + + // ePKI Root Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE-----'`)) + + // HiPKI Root CA - G1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa +Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 +YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw +qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv +Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 +lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz +Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ +KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK +FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj +HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr +y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ +/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM +a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 +fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG +SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc +SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza +ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc +XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg +iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho +L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF +Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr +kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ +vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU +YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE-----'`)) + + // CommScope Public Trust ECC Root-01 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw +TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t +bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa +Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv +cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C +flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE +hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq +hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg +2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS +Um9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE-----'`)) + + // CommScope Public Trust ECC Root-02 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw +TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t +bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa +Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv +cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL +j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU +v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq +hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n +ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV +mkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE-----'`)) + + // CommScope Public Trust RSA Root-01 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL +BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi +Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1 +NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t +U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt +MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk +YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh +suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al +DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj +WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl +P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547 +KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p +UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/ +kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO +Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB +Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U +CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ +KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ +nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+ +QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v +trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a +aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD +j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4 +Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w +lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn +YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc +icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE-----'`)) + + // CommScope Public Trust RSA Root-02 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL +BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi +Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2 +NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t +U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt +MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE +NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0 +kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C +rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz +hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2 +LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs +n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku +FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5 +kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3 +wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v +wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs +5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ +KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3 ++VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme +APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq +pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT +6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF +sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt +PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d +lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670 +v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O +rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE-----'`)) + + // SecureSign Root CA12 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u +LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw +NTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD +eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS +b290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3emhF +KxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mt +p7JIKwccJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zd +J1M3s6oYwlkm7Fsf0uZlfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gur +FzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBFEaCeVESE99g2zvVQR9wsMJvuwPWW0v4J +hscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1UefNzFJM3IFTQy2VYzxV4+K +h9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsF +AAOCAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6Ld +mmQOmFxv3Y67ilQiLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJ +mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA +8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV +55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/ +yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== +-----END CERTIFICATE-----'`)) + + // SecureSign Root CA14 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM +BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u +LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw +NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD +eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS +b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/ +FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg +vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy +6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo +/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J +kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ +0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib +y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac +18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs +0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB +SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL +ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk +86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E +rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib +ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT +zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS +DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4 +2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo +FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy +K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6 +dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl +Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB +365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c +JRNItX+S +-----END CERTIFICATE-----'`)) + + // SecureSign Root CA15 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw +UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM +dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy +NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl +cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290 +IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4 +wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR +ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT +9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp +4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6 +bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= +-----END CERTIFICATE-----'`)) + + // D-TRUST BR Root CA 1 2020 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 +NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS +zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 +QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ +VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW +wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV +dWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE-----'`)) + + // D-TRUST EV Root CA 1 2020 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 +NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC +/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD +wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 +OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA +y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb +gfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE-----'`)) + + // D-TRUST Root CA 3 2013 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEDjCCAvagAwIBAgIDD92sMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD +QSAzIDIwMTMwHhcNMTMwOTIwMDgyNTUxWhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD +VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZELVRSVVNU +IFJvb3QgQ0EgMyAyMDEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xHtCkoIf7O1UmI4SwMoJ35NuOpNcG+QQd55OaYhs9uFp8vabomGxvQcgdJhl8Ywm +CM2oNcqANtFjbehEeoLDbF7eu+g20sRoNoyfMr2EIuDcwu4QRjltr5M5rofmw7wJ +ySxrZ1vZm3Z1TAvgu8XXvD558l++0ZBX+a72Zl8xv9Ntj6e6SvMjZbu376Ml1wrq +WLbviPr6ebJSWNXwrIyhUXQplapRO5AyA58ccnSQ3j3tYdLl4/1kR+W5t0qp9x+u +loYErC/jpIF3t1oW/9gPP/a3eMykr/pbPBJbqFKJcu+I89VEgYaVI5973bzZNO98 +lDyqwEHC451QGsDkGSL8swIDAQABo4IBBTCCAQEwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUP5DIfccVb/Mkj6nDL0uiDyGyL+cwDgYDVR0PAQH/BAQDAgEGMIG+ +BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQv +Q049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDEzLE89RC1UcnVzdCUyMEdt +YkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8v +Y3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDEzLmNybDAN +BgkqhkiG9w0BAQsFAAOCAQEADlkOWOR0SCNEzzQhtZwUGq2aS7eziG1cqRdw8Cqf +jXv5e4X6xznoEAiwNStfzwLS05zICx7uBVSuN5MECX1sj8J0vPgclL4xAUAt8yQg +t4RVLFzI9XRKEBmLo8ftNdYJSNMOwLo5qLBGArDbxohZwr78e7Erz35ih1WWzAFv +m2chlTWL+BD8cRu3SzdppjvW7IvuwbDzJcmPkn2h6sPKRL8mpXSSnON065102ctN +h9j8tGlsi6BDB2B4l+nZk3zCRrybN1Kj7Yo8E6l7U0tJmhEFLAtuVqwfLoJs4Gln +tQ5tLdnkwBXxP/oYcuEVbSdbLTAoK59ImmQrme/ydUlfXA== +-----END CERTIFICATE-----'`)) + + // D-TRUST Root Class 3 CA 2 2009 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE-----'`)) + + // D-TRUST Root Class 3 CA 2 EV 2009 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE-----'`)) + + // D-Trust SBR Root CA 1 2022 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICXjCCAeOgAwIBAgIQUs/kjG2gSvc/gpcMgAmMlTAKBggqhkjOPQQDAzBJMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSMwIQYDVQQDExpELVRy +dXN0IFNCUiBSb290IENBIDEgMjAyMjAeFw0yMjA3MDYxMTMwMDBaFw0zNzA3MDYx +MTI5NTlaMEkxCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgxIzAh +BgNVBAMTGkQtVHJ1c3QgU0JSIFJvb3QgQ0EgMSAyMDIyMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEWZM59oxJZijXYQzIq38Moy3foqR8kito1S5+HkDLtGhJfxKhq39X +nxkuYy5b/mZxDDMPud5rxIjDse/sOUDjlqvb5XuuH9z5r0aaakYGL8c3ZIsXYv6W +w6LuhOCwlzm8o4GPMIGMMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPEpox4B +Eh09dVZNx1B8xRmqDxi3MA4GA1UdDwEB/wQEAwIBBjBKBgNVHR8EQzBBMD+gPaA7 +hjlodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Nicl9yb290X2Nh +XzFfMjAyMi5jcmwwCgYIKoZIzj0EAwMDaQAwZgIxAJf53q5Lj5i1HkB/Mn1NVEPa +ic3CqpI80YIec8/6TJIg+2MnxfVzPQk996dhhozzagIxAOcvfLj1JYw7OR82q431 +hqIu4Xpk2mc5Av7+Mz/Zc7ZYWzr8sqTZYHh3zHmnpq5VvQ== +-----END CERTIFICATE-----'`)) + + // D-Trust SBR Root CA 2 2022 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFrDCCA5SgAwIBAgIQVNWjlR49lbpyG5rQMSFKujANBgkqhkiG9w0BAQ0FADBJ +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSMwIQYDVQQDExpE +LVRydXN0IFNCUiBSb290IENBIDIgMjAyMjAeFw0yMjA3MDcwNzMwMDBaFw0zNzA3 +MDcwNzI5NTlaMEkxCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgx +IzAhBgNVBAMTGkQtVHJ1c3QgU0JSIFJvb3QgQ0EgMiAyMDIyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAryy8jjaM62SvUWrWbjxekTrqmsPKbPuqJ55k +IqlA37koRVrsU2EWKJjCiqR1eFCE3fogSJIHZUE1ZlESdGGdBwaFOTFXeyg/1Zyl +7FrpHEsnn84nBvM39VLYETMWQTof9WN4ZWOGyb/IAQQfbu7i7KwM7oKS4vYaDT85 ++Z1lk634uQXBPfg3gVbDoP4F7OCUFjojFgTapgqThXJtYTuhjUXW43++Fb02hAj2 +C4NrJqqiveCw56rgrmfE04KlDKmk8DN5DVA/8O+QPSS5f9IgbOqX87+c3EfeCWG9 +lHmVWgJ2NWDERyIN93ZjA9PG+4PGXaut7WklKwNbTSUAQeOMhxdSqOAFK0NNFBPK +5z9DIrw3pHXx9r867zIeru5YhpByugSsQEjvXMR4p6mPJ1rLeuxY8sIIWJBtTQOF +eXEVBQ5OPvnfDwX3XxRIViENM5KxrIzlGP6/D+7gBKq9IfJYtlyJCosYCSIaszXG +ZsL1MxWZgOAI+ZYvE4zu2reIxOk3tddq1zqETatwjNNOFFWgohD8ZNpn6PHLM93J +moqPli9Ygdn4mgBDzJD7VXb7huM3ASgMb/TpWU0Vd1FCSsw0uIBDUIHvV6UT26eU +eQ9Lyn4Xfa+jIWTocVVWjwawR+xZD11wWywWQvCGnnXea01ImITiVxi2nIKZZTqL +gHhXDEkCAwEAAaOBjzCBjDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRds4CU +G+WGv2i6FDSk9u5t8t3f5zAOBgNVHQ8BAf8EBAMCAQYwSgYDVR0fBEMwQTA/oD2g +O4Y5aHR0cDovL2NybC5kLXRydXN0Lm5ldC9jcmwvZC10cnVzdF9zYnJfcm9vdF9j +YV8yXzIwMjIuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA0VC5YGFbNSr2X0/V9K9yv +D1HhTbwhS5P0AEQTBxALJRg+SFmW96Hhk5B4Zho9I+siqwGmjgxRM+ZtjDHurKQB +cDlI3sdmLGsNy3Ofh5LpPkcfuO8v7rdWjEiJ8DinFTmy7sA/F6RzAgicvAaKpMK3 +YWH5w9vE0Hp8Yd6xWJH13WVMLwv46z217Yq+dxy6WQISZnHlmCfODj2vUaJF+YL7 +WqWUcPeLhMNMZSWbe+IfMHCzQI467r3052jFnckpR3EOk8i1SE71ZrsHiHFpa3tI +jm/wEcS0yXAUmCC97afqAdpupZsS/j5EMLPw63VSwPTD+ncmpHeCLW/zKB5OlfAw +94n4LKJQW/K+Mn5sVNtyySpa4By2C9hSmlmh47ABJ8WgFlBm3OuubfSbWz2EbVuH +56mJu2644JtTicD/LkAaiUQuGENnOOR8cl/ZoyklQUE9HHcbZKjDVe5jcWZig/R/ +JpmgVDuhEm1wYs7T+bi9IvzUmtS74jgWL7d9OcKwqQPpnM9+GI123F8Ru+tC7FAJ +PlzskDHYGnK6P2kH7pg0wjSk1toT1qmE8gCGwFS6HhGw4rnEB7SR56rmMVZvsUTE +KmK8ybBlnDT8DBpT3yEXu8JtoQrm8bCqRAlQSTh6XXHiMS4ZsN+VQgR9hIjOCiNn +azidFt4G/ihwOKVarvyD7Q== +-----END CERTIFICATE-----'`)) + + // T-TeleSec GlobalRoot Class 2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE-----'`)) + + // T-TeleSec GlobalRoot Class 3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE-----'`)) + + // Telekom Security SMIME ECC Root 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICRzCCAc2gAwIBAgIQFSrdFMkY0aRWQIamJa8HXzAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMS0wKwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIEVDQyBSb290IDIw +MjEwHhcNMjEwMzE4MTEwODMwWhcNNDYwMzE3MjM1OTU5WjBlMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMS0wKwYD +VQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIEVDQyBSb290IDIwMjEwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAASwGY+ia7XHzQ8wmTcMw2Bb8fEnIFU9wJKLq1ehb3OD +IcJDEwxeiarHBTV5k2KQ1l0TH9F6oLyeEKdmfEYKsFdsv+ZUOTghbBJccczTWl9t +t6eG37Pf7sLniUGWNfYvSrWjQjBAMB0GA1UdDgQWBBQrywEMY8NTEqWoV6/QnIP7 +vZA6SzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQD +AwNoADBlAjEA1rxIkodHA8dwOyW2H65GZ3N0ACdL5KUEogPfXiitbl4DyN1onLa/ +lBBIlS8P/xiLAjABQDOel5dNBfJ0VAzNOf1qawnBJD9hjjiht+jXRBURYv8OYTdH +S0B/Sl+yZ1pzdcI= +-----END CERTIFICATE-----'`)) + + // Telekom Security SMIME RSA Root 2023 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgIQDH5i9XlzO51Djotj7ZGVuDANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMS0wKwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIFJTQSBSb290 +IDIwMjMwHhcNMjMwMzI4MTIwOTIyWhcNNDgwMzI3MjM1OTU5WjBlMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMS0w +KwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIFJTQSBSb290IDIwMjMwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDvxQ6LvjLSZ0f/Ckxnsyq/yMPF +keu1xx6R4WaoiItVIIAfUV53l54ZClzHazchfAM2AfSIJdmoLkGq/Ngm4JZAYnmu +V54DOBocsncUPumhctDk4DfRF0btUFx6WMX4K/d1L8+BnlostzqsoFmYBFEM/0nF +UP0e00eFSzNPoje1rwSaJzKdVtU/VWHji2+uUf6X/mkH+mJbJuYUeRWlEziuXze+ +lErWDYAWaaSRsjpJmHWdRhCKXHp/hKXorx7Hq7NaRrWjS/WmIzYARrHbBbYbzp56 +Mlya1XLDnYZNK4TTHrWI2hB4nCLDOyO16xMHvW9T7Jvsm9Nl9QcJ412nmbV+ho7V +Av+3hQnjRxTdlmYYNN4I1d/LGJliCyvsAF1SRNPGlvwyViWRz80ZO5U5PgKHmWO2 +1T40eg8RdYG8fQTKYLQoddcCUd1SAC7H/YnxXPPLpCcSOI+7+4nw5MQ4LL6CoHFh +YpGPSAwvK6mw8csQBOd0vzeQ708qQzWXEsYqcA3eLFVHeWMp9cofagZSHK4tJCKD +Iq/QqjC3Kh//ZSNYZZPIjn1AEDGGeNlVyzww8N5RKgA20idFX9jooSE9fkZWOylF +8R0FCc62QzDcRZAQMEyka4aLPz0vMZFx7ya59r6dsGzfEe5YP0N5hjmA8SYXB5jw +maowLENZFM7t4kAThQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FJrOrCrsAfplcN6XnfHSAIylo2S7MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw +FoAUms6sKuwB+mVw3ped8dIAjKWjZLswDQYJKoZIhvcNAQEMBQADggIBAONQ/fVA +FiIJljoNqe+B5y4y8KHxSV57iA0Ecte+Z6i6He5Qu3JuetG7DHIwRsjV1wISFplO +Ht9alu6Pkb6uhvgQd6XEbkdhwPIm2U9haAVIdQgVpaF71biziXnm7fHzYQCGey4x +/qNc+Hk9tFuIe+Ajuw2hF/rLaA2Yd3EI4m1DdGvENsWUQaQA1lctmYqLIBIVAjIO +0knsgUjFaidS17JzVVOWPJ5PTLWg0E9X0GcoSGS+xri67GTPyHvFaucq5llXttbU +1sBnXNmeKAlAv/OpNTFlYAPLGWyClQMeXz/hvepJceVbtwtHFhsgiW2UmQx+iGwd +DfS3IRpZl6zL6L4XH5V8U5uvUFKqjQsur1rXYPIqaSq57lRwGKq99aE/0t2hYxkA ++KcM66N58nBZo/iiEgPsE//kAoY218HDpLXUpMI3RbaUcD3FveujFR3jNnoVaSpW +NDnPpZo2qsjtebzP9s4EUwvaslAjfLw+Jq3wDkO7JsuuwkDeNx8KoFHNY522T9jG +R3y82LTtnovzEeKotT7srnA+fiK7NUgXYGIUkTCjdj2mUTaLHw3dajEcpe3dlqNu +cg8TTaqnqVx4+QMSGJM3RRKJPfi+yr3ZvgzZGGSnyEE+dYIhOH1l9KDUE0sHeCn5 +nX7Mhz/E2i6I3eML3FpRWunZEk+eAtv3BSVR +-----END CERTIFICATE-----'`)) + + // Telekom Security TLS ECC Root 2020 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw +MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx +JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE +AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O +tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP +f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA +MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di +z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn +27iQ7t0l +-----END CERTIFICATE-----'`)) + + // Telekom Security TLS RSA Root 2023 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy +MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC +REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG +A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 +cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV +cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA +U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 +Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug +BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy +8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J +co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg +8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 +rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 +mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg ++y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX +gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ +pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm +9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw +M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd +GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ +CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t +xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ +w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK +L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj +X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q +ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm +dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE-----'`)) + + // Baltimore CyberTrust Root + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE-----'`)) + + // DigiCert Assured ID Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE-----'`)) + + // DigiCert Assured ID Root G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE-----'`)) + + // DigiCert Assured ID Root G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE-----'`)) + + // DigiCert Global Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE-----'`)) + + // DigiCert Global Root G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE-----'`)) + + // DigiCert Global Root G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE-----'`)) + + // DigiCert High Assurance EV Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE-----'`)) + + // DigiCert SMIME ECC P384 Root G5 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIQBT9uoAYBcn3tP8OjtqPW7zAKBggqhkjOPQQDAzBQMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKDAmBgNVBAMTH0Rp +Z2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xKDAmBgNVBAMTH0RpZ2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQWnVXlttT7+2drGtShqtJ3lT6I5QeftnBm +ICikiOxwNa+zMv83E0qevAED3oTBuMbmZUeJ8hNVv82lHghgf61/6GGSKc8JR14L +HMAfpL/yW7yY75lMzHBrtrrQKB2/vgSjQjBAMB0GA1UdDgQWBBRzemuW20IHi1Jm +wmQyF/7gZ5AurTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNnADBkAjA3RPUygONx6/Rtz3zMkZrDbnHY0iNdkk2CQm1cYZX2kfWn +CPZql+mclC2YcP0ztgkCMAc8L7lYgl4Po2Kok2fwIMNpvwMsO1CnO69BOMlSSJHW +Dvu8YDB8ZD8SHkV/UT70pg== +-----END CERTIFICATE-----'`)) + + // DigiCert SMIME RSA4096 Root G5 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQBfa6BCODRst9XOa5W7ocVTANBgkqhkiG9w0BAQwFADBP +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJzAlBgNVBAMT +HkRpZ2lDZXJ0IFNNSU1FIFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBa +Fw00NjAxMTQyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy +dCwgSW5jLjEnMCUGA1UEAxMeRGlnaUNlcnQgU01JTUUgUlNBNDA5NiBSb290IEc1 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4Gpb2fj5fey1e+9f3Vw0 +2Npd0ctldashfFsA1IJvRYVBiqkSAnIy8BT1A3W7Y5dJD0CZCxoeVqfS0OGr3eUE +G+MfFBICiPWggAn2J5pQ8LrjouCsahSRtWs4EHqiMeGRG7e58CtbyHcJdrdRxDYK +mVNURCW3CTWGFwVWkz1BtwLXYh+KkhGH6hFt6ggR3LF4SEmS9rRRgHgj2P7hVho6 +kBNWNInV4pWLX96yzPs/OLeF9+qevy6hLi9NfWoRLjag/xEIBJVV4Bs7Z5OplFXq +Mu0GOn/Cf+OtEyfRNEGzMMO/tIj4A4Kk3z6reHegWZNx593rAAR7zEg5KOAeoxVp +yDayoQuX31XW75GcpPYW91EK7gMjkdwE/+DdOPYiAwDCB3EaEsnXRiqUG83Wuxvu +v75NUFiwC80wdin1z+W2ai92sLBpatBtZRg1fpO8chfBVULNL8Ilu/T9HaFkIlRd +4p5yQYRucZbqRQe2XnpKhp1zZHc4A9IPU6VVIMRN/2hvVanq3XHkT9mFo3xOKQKe +CwnyGlPMAKbd0TT2DcEwsZwCZKw17aWwKbHSlTMP0iAzvewjS/IZ+dqYZOQsMR8u +4Y0cBJUoTYxYzUvlc4KGjOyo1nlc+2S73AxMKPYXr+Jo1haGmNv8AdwxuvicDvko +Rkrh/ZYGRXkRaBdlXIsmh1sCAwEAAaNCMEAwHQYDVR0OBBYEFNGj1FcdT1XbdUxc +Qp5jFs60xjsfMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBDAUAA4ICAQAHpwreU7ua63C/sjaQzeSnuPEM5F1aHXhl/Mm4HiMRV3xp +NW0B/1NQvwcOuscBP1gqlHUDqxwLI9wbih43PR1Yj3PZsypv3xCgWwynyrB/uSSi +ATUy5V5GQevYf3PnQumkUSZ3gQqo6w8KUJ1+iiBn/AuOOhHTxYxgGNlLsfzU8bRJ +Tq6H4dH7dqFf8wbPl5YM6Z51gVxTDSL8NuZJbnTbAIWNfCKgjvsQTNRiE1vvS3Im +i/xOio/+lxBTxXiLQmQbX+CJ/bsJf1DgVIUmEWodZflJKdx8Nt/7PffSrO4yjW6m +fTmcRcTKDfU7tHlTpS9Wx1HFikxkXZBDI45rTBd4zOi/9TvkqEjPrZsM3zJK09kS +jiN4DS2vn6+ePAnClwDtOmkccT8539OPxGb17zaUD/PdkraWX5Cm3XOqpiCUlCVq +CQxy5BMjYEyjyhcue2cA29DN6nofOSZXiTB3y07llUVPX/s2XD35ILU6ECVPkzJa +7sGW6OlWBLBJYU3seKidGMH/2OovVu+VK3sEXmfjVUDtOQT5C3n1aoxcD4makMfN +i97bJjWhbs2zQvKiDzsMjpP/FM/895P35EEIbhlSEQ9TGXN4DM/YhYH4rVXIsJ5G +Y6+cUu5cv/DAWzceCSDSPiPGoRVKDjZ+MMV5arwiiNkMUkAf3U4PZyYW0q0XHA== +-----END CERTIFICATE-----'`)) + + // DigiCert TLS ECC P384 Root G5 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE-----'`)) + + // DigiCert TLS RSA4096 Root G5 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE-----'`)) + + // DigiCert Trusted Root G4 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE-----'`)) + + // DIGITALSIGN GLOBAL ROOT ECDSA CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICajCCAfCgAwIBAgIUNi2PcoiiKCfkAP8kxi3k6/qdtuEwCgYIKoZIzj0EAwMw +ZDELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmljYWRv +cmEgRGlnaXRhbDEpMCcGA1UEAwwgRElHSVRBTFNJR04gR0xPQkFMIFJPT1QgRUNE +U0EgQ0EwHhcNMjEwMTIxMTEwNzUwWhcNNDYwMTE1MTEwNzUwWjBkMQswCQYDVQQG +EwJQVDEqMCgGA1UECgwhRGlnaXRhbFNpZ24gQ2VydGlmaWNhZG9yYSBEaWdpdGFs +MSkwJwYDVQQDDCBESUdJVEFMU0lHTiBHTE9CQUwgUk9PVCBFQ0RTQSBDQTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABG4Lo6szTRzqSuj8BI0UoH3wCCxfg6uT0dJ7utdJ +fY/sElBf1LnL5fD5M2MfyVfsQNgRC5foUhbMKY70BoYeONw9V8Tuqr3IVAQmWicT +UUc9Hx8ajqiVpDPQzEfMbbj8SKNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBTOr0qLGnXi8TjnAvAWrV7qZNV7tDAdBgNVHQ4EFgQUzq9Kixp14vE45wLw +Fq1e6mTVe7QwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMAqIxHGc +RANNjbTHvKiu2TAnNWprFmPX/OdZ4aeJG0wxmiNVRObzQyHVRydvbVcBqgIxAPuy +6uKXf1G1n0jrvG81iahkcKtXds3AxhRgyn/iggBz98w16o4km+UIWccEjHN4/g== +-----END CERTIFICATE-----'`)) + + // DIGITALSIGN GLOBAL ROOT RSA CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIUXVnIyqsJV/XmtdoplARq/8XUlYcwDQYJKoZIhvcNAQEN +BQAwYjELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmlj +YWRvcmEgRGlnaXRhbDEnMCUGA1UEAwweRElHSVRBTFNJR04gR0xPQkFMIFJPT1Qg +UlNBIENBMB4XDTIxMDEyMTEwNTAzNFoXDTQ2MDExNTEwNTAzNFowYjELMAkGA1UE +BhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmljYWRvcmEgRGlnaXRh +bDEnMCUGA1UEAwweRElHSVRBTFNJR04gR0xPQkFMIFJPT1QgUlNBIENBMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyIe2ONMc8N4S+IPHxIriibi0Inp4 ++AxmUWh2NwrVT8JaCLgWXPdyAQk3hIEqVGvXktBs+qinQxI06w7bNw8p/ooxUULo +S5yQqMgsEdP9oCl+zt6U9oLgWLRORSXxIvI90w97VBrcMrbWUU5+QbRXuCzGuQ4u +ylfx1cjTWOel6UIRrtMgJZRp14/Kog3D058HaD8V0mcuU/12gpsLc6kpDZ4RkxQI +mOyeVBJKVqIGFexrbC6SYC6GDa6CH1FN47IH1xAZVyL2qWlEhPPZPaAGv8yIfn/1 +zlulwipqdELqb6b/+Wix0F+9kdJVbzNXTB6d5OKLwYVloOBqnAAAiJLdWAgW8nAx +qBzh3r1OcenWvn61oVrDTfe/m72UpP31qlOTRskmAQRwxKBxus4lZvuRflVw7kkK +TWJ/wlCacvIYZ53pRag0hOj4gfbRWiIeB087s3/dEaVz3L6pGTppqW0bMuKJqqUn +C1p+dOIPZDldfly5wRf8x41eyewk7dLyP3qERTcCvj5rWcTmWxZtwKqeqrVZLixw +VZzMmZaYJFTRjtrKtBG0t3BDH2+QCyCgqHYTZdvbI1p1S6ELMXcK7n1oYRoTjOpR +flxWo1dMXaHrE2W/VBTM8+7c1+w8l/J4Vrjfclxw/M4G3Z/SBzHv51KRns2618AY +RAcxZUkyaRNK648CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW +gBS1Nrw8jBqrLPZZGS2DFNqTJRXWhjAdBgNVHQ4EFgQUtTa8PIwaqyz2WRktgxTa +kyUV1oYwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQAU+zElODH4 +ygiyI3Y4rfjTWfXMtFcl4US+fvwW7K76Jp9PZxZKVvD97ccZATSOkFot1oBc7HHS +gSWCHgBx35rR1R0iu9Gl82IPtOvcJHP+plbNmhTFBDUWMaIH66UA4rb4X3L9P2FJ +jt5+TTjXeh50N2xR3L4ABLg4FPMgwe2bpyP9DUKEHX/yc8PQeGPxn+zXW+nxvmyg +SwOejWnhFNqIEIEjU//aVCsLxrmWlQQYRvN7qJfYW2ik5DgcDkXlmNMJrppe7LN5 +DTly8vSUnQ6eYCLmqPZMhc0HgjpoOc09X+M49LavO2tKn2BRRaJAAuWqDOM+0XjU +onScJroFmihwSj6mC9AdSfC6+K5BEH6kBxK9qM8pPVe7x/FDRwA+rnAYWiB7Ccs6 +OnCA5UxgmMEVwR1K98jwm+FyreddaFgLBLGMvJ+3+26LWwRV++sjVdd4UNoly74n +NrskGnkcUdH+E7v/eCzcpL4v9sVLU8+nTJlecKxZiASuZAS/e6Z6TdPod72hflAV +8+9JMIVNIVeq2yx1l62BAYeisXCdHgZaA2CxP6ZtgizUFLGBpeg9iB20cixYN4qO +OJS4c92p4Lj2d6KzfFjermk6tYulGrvy2HQGnP1icyAhdrF+cJ4Z1OsXYhk4mc02 +K0f+McvfueSsCNPYpuvUnn5LZKRVXSsXyQ== +-----END CERTIFICATE-----'`)) + + // CA Disig Root R2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE-----'`)) + + // GLOBALTRUST 2020 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE-----'`)) + + // emSign ECC Root CA - C3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE-----'`)) + + // emSign ECC Root CA - G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE-----'`)) + + // emSign Root CA - C1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE-----'`)) + + // emSign Root CA - G1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE-----'`)) + + // AffirmTrust Commercial + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE-----'`)) + + // AffirmTrust Networking + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE-----'`)) + + // AffirmTrust Premium + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE-----'`)) + + // AffirmTrust Premium ECC + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE-----'`)) + + // Entrust Root Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE-----'`)) + + // Entrust Root Certification Authority - EC1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE-----'`)) + + // Entrust Root Certification Authority - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE-----'`)) + + // Entrust Root Certification Authority - G4 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE-----'`)) + + // Entrust.net Certification Authority (2048) + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE-----'`)) + + // Atos TrustedRoot 2011 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE-----'`)) + + // Atos TrustedRoot Root CA ECC G2 2020 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICMTCCAbagAwIBAgIMC3MoERh0MBzvbwiEMAoGCCqGSM49BAMDMEsxCzAJBgNV +BAYTAkRFMQ0wCwYDVQQKDARBdG9zMS0wKwYDVQQDDCRBdG9zIFRydXN0ZWRSb290 +IFJvb3QgQ0EgRUNDIEcyIDIwMjAwHhcNMjAxMjE1MDgzOTEwWhcNNDAxMjEwMDgz +OTA5WjBLMQswCQYDVQQGEwJERTENMAsGA1UECgwEQXRvczEtMCsGA1UEAwwkQXRv +cyBUcnVzdGVkUm9vdCBSb290IENBIEVDQyBHMiAyMDIwMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEyFyAyk7CKB9XvzjmYSP80KlblhYWwwxeFaWQCf84KLR6HgrWUyrB +u5BAdDfpgeiNL2gBNXxSLtj0WLMRHFvZhxiTkS3sndpsnm2ESPzCiQXrmBMCAWxT +Hg5JY1hHsa/Co2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFFsfxHFs +shufvlwfjP2ztvuzDgmHMB0GA1UdDgQWBBRbH8RxbLIbn75cH4z9s7b7sw4JhzAO +BgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAOzgmf3d5FTByx/oPijX +FVlKgspTMOzrNqW5yM6TR1bIYabhbZJTlY/241VT8N165wIxALCH1RuzYPyRjYDK +ohtRSzhUy6oee9flRJUWLzxEeC4luuqQ5OxS7lfsA4TzXtsWDQ== +-----END CERTIFICATE-----'`)) + + // Atos TrustedRoot Root CA ECC TLS 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w +LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w +CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 +MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF +Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X +tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 +AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 +KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD +aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu +CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo +9H1/IISpQuQo +-----END CERTIFICATE-----'`)) + + // Atos TrustedRoot Root CA RSA G2 2020 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIMR7opRlU+FpKXsKtAMA0GCSqGSIb3DQEBDAUAMEsxCzAJ +BgNVBAYTAkRFMQ0wCwYDVQQKDARBdG9zMS0wKwYDVQQDDCRBdG9zIFRydXN0ZWRS +b290IFJvb3QgQ0EgUlNBIEcyIDIwMjAwHhcNMjAxMjE1MDg0MTIzWhcNNDAxMjEw +MDg0MTIyWjBLMQswCQYDVQQGEwJERTENMAsGA1UECgwEQXRvczEtMCsGA1UEAwwk +QXRvcyBUcnVzdGVkUm9vdCBSb290IENBIFJTQSBHMiAyMDIwMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAljGFSqoPMv554UOHnPsjt45/DVS9x2KTd+Qc +NQR2owOLIu7EhN2lk25uso4JA+tRFjEXqmkVGA5ndCNe6pp9tTk+PYKpa+H+qRyw +rVpNTHiDQYvP8h1impgEnGPpq2X+SB0kZQdHPrmRLumdm38aNak0sLflcDPvSnJR +tge/YD8qn51U3/PXlElRA1pAqWjdEVlc+HamvFBSEO2s7JXg1INrSdoKT5mD3jKD +SINnlbJ+54GFPc2C98oC7W2IXQiNuDW/KmkwmbtL0UHbRaCTmVGBkDYIqoq26I+z +y+7lRg1ydfVJbOGify+87YSmN+7ewk85Tvae8MnRmzCdSW3h2v8SEIzW5Zl7BbZ9 +sAnHpPiyHDmVOTP0Nc4lYnuwXyDzy234bFIUZESP08ipdgflr3GZLS0EJUh2r8Pn +zEPyB7xKJCQ33fpulAlvTF4BtP5U7COWpV7dhv/pRirx6NzspT2vb6oOD7R1+j4I +uSZFT2aGTLwZuOHVNe6ChMjTqxLnzXMzYnf0F8u9NHYqBc6V5Xh5S56wjfk8WDiR +6l6HOMC3Qv2qTIcjrQQgsX52Qtq7tha6V8iOE/p11QhMrziRqu+P+p9JLlR8Clax +evrETi/Uo/oWitCV5Zem/8P8fA5HWPN/B3sS3Fc/LeOhTVtSTDOHmagJe2x+DvLP +VkKe6wUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQgJfMH +/adv8ZbukRBpzJrvfchoeDAdBgNVHQ4EFgQUICXzB/2nb/GW7pEQacya733IaHgw +DgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQAkK06Y8h0X7dl2JrYw +M+hpRaFRS1LYejowtuQS6r+fTOAEpPY1xv6hMPdThZKtVAVXX5LlKt42J557E0fJ +anWv/PM35wz1PQFztWlR+L1Z0boL+Lq6ZCdDs3yDlYrnnhOW129KlkFJiw4grRbG +96aHW4gSiYuJyhLSVq8iASFG6auYP6eI3uTLKpp1Gfo5XgkF1wMyGrgXUQjHAEB9 +9L74DFn0aXZu06RYW14mc+RCVQZeeEAP0zif7yZRcHSR8XdiAejZy+uh3zkyHbtr +/XH+68+l5hT9AIATxpoASLCZBemugEj7CT9RFLW552BNTcovgSHuUgxletz1iUlM +MJI0WIAyWbEN/yRhD+cKQtB7vPiOJ0c/cJ0n2bYGPaW7y16Prg5Tx5xqbztMD6NA +cKiaB87UblsHotLiVLa9bzNyY61RmOGPdvFqBzgl/vZizl/bY8Jume8G3LneGRro +VD190nZ12V4+MkinjPKecgz4uFi4FyOlFId1WHoAgQciOWpMlKC1otunLMGw8aOb +wEz3bXDqMZ/xrn0+cyjZod/6k/CbsPDizSUgde/ifTIFyZt27su9MR75lJhLJFhW +SMDeBky9pjRd7RZhY3P7GeL6W9iXddRtnmA5XpSLAizrmc5gKm4bjKdLvP025pgf +ZfJ/8eOPTIBGNli2oWXLzhxEdQ== +-----END CERTIFICATE-----'`)) + + // Atos TrustedRoot Root CA RSA TLS 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM +MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx +MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 +MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD +QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z +4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv +Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ +kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs +GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln +nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh +3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD +0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy +geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 +ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB +c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI +pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs +o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ +qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw +xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM +rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 +AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR +0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY +o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 +dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE +oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE-----'`)) + + // GlobalSign + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE-----'`)) + + // GlobalSign + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE-----'`)) + + // GlobalSign + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE-----'`)) + + // GlobalSign Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE-----'`)) + + // GlobalSign Root E46 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE-----'`)) + + // GlobalSign Root R46 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE-----'`)) + + // GlobalSign Secure Mail Root E45 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICITCCAaegAwIBAgIQdlP+qicdlUZd1vGe5biQCjAKBggqhkjOPQQDAzBSMQsw +CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMf +R2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IEU0NTAeFw0yMDAzMTgwMDAwMDBa +Fw00NTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxT +aWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJvb3Qg +RTQ1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+XmLgUc3iZY/RUlQfxomC5Myfi7A +wKcImsNuj5s+CyLsN1O3b4qwvCc3S22pRjvZH/+loUS7LXO/nkEHXFObUQg6Wrtv +OMcWkXjCShNpHYLfWi8AiJaiLhx0+Z1+ZjeKo0IwQDAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3xNei1/CQAL9VreUTLYe1aaxFJYw +CgYIKoZIzj0EAwMDaAAwZQIwE7C+13EgPuSrnM42En1fTB8qtWlFM1/TLVqy5IjH +3go2QjJ5naZruuH5RCp7isMSAjEAoGYcToedh8ntmUwbCu4tYMM3xx3NtXKw2cbv +vPL/P/BS3QjnqmR5w+RpV5EvpMt8 +-----END CERTIFICATE-----'`)) + + // GlobalSign Secure Mail Root R45 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIQdlP+qExQq5+NMrUdA49X3DANBgkqhkiG9w0BAQwFADBS +MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UE +AxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IFI0NTAeFw0yMDAzMTgwMDAw +MDBaFw00NTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJv +b3QgUjQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3HnMbQb5bbvg +VgRsf+B1zC0FSehL3FTsW3eVcr9/Yp2FqYokUF9T5dt0b6QpWxMqCa2axS/C93Y7 +oUVGqkPmJP4rsG8ycBlGWnkmL/w9fV9ky1fMYWGo2ZVu45Wgbn9HEhjW7wPJ+4r6 +mr2CFalVd0sRT1nga8Nx8wzYVNWBaD4TuRUuh4o8RCc2YiRu+CwFcjBhvUKRI8Sd +JafZVJoUozGtgHkMp2NsmKOsV0czH2WW4dDSNdr5cfehpiW1QV3fPmDY0fafpfK4 +zBOqj/mybuGDLZPdPoUa3eixXCYBy0mF/PzS1H+FYoZ0+cvsNSKiDDCPO6t561by ++kLz7fkfRYlAKa3qknTqUv1WtCvaou11wm6rzlKQS/be8EmPmkjUiBltRebMjLnd +ZGBgAkD4uc+8WOs9hbnGCtOcB2aPxxg5I0bhPB6jL1Bhkgs9K2zxo0c4V5GrDY/G +nU0E0iZSXOWl/SotFioBaeepfeE2t7Eqxdmxjb25i87Mi6E+C0jNUJU0xNgIWdhr +JvS+9dQiFwBXya6bBDAznwv731aiyW5Udtqxl2InWQ8RiiIbZJY/qPG3JEqNPFN8 +bYN2PbImSHP1RBYBLQkqjhaWUNBzBl27IkiCTApGWj+A/1zy8pqsLAjg1urwEjiB +T6YQ7UarzBacC89kppkChURnRq39TecCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgGG +MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKCTFShu7o8IsjXGnmJ5dKexDit7 +MA0GCSqGSIb3DQEBDAUAA4ICAQBFCvjRXKxigdAE17b/V1GJCwzL3iRlN/urnu1m +9OoMGWmJuBmxMFa02fb3vsaul8tF9hGMOjBkTMGfWcBGQggGR2QXeOCVBwbWjKKs +qdk/03tWT/zEhyjftisWI8CfH1vj1kReIk8jBIw1FrV5B4ZcL5fi9ghkptzbqIrj +pHt3DdEpkyggtFOjS05f3sH2dSP8Hzx4T3AxeC+iNVRxBKzIxG3D9pGx/s3uRG6B +9kDFPioBv6tMsQM/DRHkD9Ik4yKIm59fRz1RSeAJN34XITF2t2dxSChLJdcQ6J9h +WRbFPjJOHwzOo8wP5McRByIvOAjdW5frQmxZmpruetCd38XbCUMuCqoZPWvoajB6 +V+a/s2o5qY/j8U9laLa9nyiPoRZaCVA6Mi4dL0QRQqYA5jGY/y2hD+akYFbPedey +Ttew+m4MVyPHzh+lsUxtGUmeDn9wj3E/WCifdd1h4Dq3Obbul9Q1UfuLSWDIPGau +l+6NJllXu3jwelAwCbBgqp9O3Mk+HjrcYpMzsDpUdG8sMUXRaxEyamh29j32ahNe +JJjn6h2az3iCB2D3TRDTgZpFjZ6vm9yAx0OylWikww7oCkcVv1Qz3AHn1aYec9h6 +sr8vreNVMJ7fDkG84BH1oQyoIuHjAKNOcHyS4wTRekKKdZBZ45vRTKJkvXN5m2/y +s8H2PA== +-----END CERTIFICATE-----'`)) + + // Go Daddy Class 2 Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE-----'`)) + + // Go Daddy Root Certificate Authority - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE-----'`)) + + // Starfield Class 2 Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE-----'`)) + + // Starfield Root Certificate Authority - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE-----'`)) + + // GlobalSign + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE-----'`)) + + // GTS Root R1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE-----'`)) + + // GTS Root R2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE-----'`)) + + // GTS Root R3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE-----'`)) + + // GTS Root R4 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE-----'`)) + + // Hongkong Post Root CA 3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE-----'`)) + + // ACCVRAIZ1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE-----'`)) + + // AC RAIZ FNMT-RCM + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE-----'`)) + + // AC RAIZ FNMT-RCM SERVIDORES SEGUROS + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE-----'`)) + + // Staat der Nederlanden Root CA - G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----END CERTIFICATE-----'`)) + + // TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE-----'`)) + + // HARICA Client ECC Root CA 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICWjCCAeGgAwIBAgIQMWjZ2OFiVx7SGUSI5hB98DAKBggqhkjOPQQDAzBvMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEnMCUGA1UEAwweSEFSSUNBIENsaWVudCBFQ0Mg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDMzNFoXDTQ1MDIxMzExMDMzM1owbzEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJzAlBgNVBAMMHkhBUklDQSBDbGllbnQgRUND +IFJvb3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABAcYrZWWlNBcD4L3 +KkD6AsnJPTamowRqwW2VAYhgElRsXKIrbhM6iJUMHCaGNkqJGbcY3jvoqFAfyt9b +v0mAFdvjMOEdWscqigEH/m0sNO8oKJe8wflXhpWLNc+eWtFolaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUUgjSvjKBJf31GpfsTl8au1PNkK0wDgYDVR0P +AQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMEwxRUZPqOa+w3eyGhhLLYh7WOar +lGtEA7AX/9+Cc0RRLP2THQZ7FNKJ7EAM7yEBLgIwL8kuWmwsHdmV4J6wuVxSfPb4 +OMou8dQd8qJJopX4wVheT/5zCu8xsKsjWBOMi947 +-----END CERTIFICATE-----'`)) + + // HARICA Client RSA Root CA 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFqjCCA5KgAwIBAgIQVVL4HtsbJCyeu5YYzQIoPjANBgkqhkiG9w0BAQsFADBv +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEnMCUGA1UEAwweSEFSSUNBIENsaWVudCBS +U0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTg0NloXDTQ1MDIxMzEwNTg0NVow +bzELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBS +ZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJzAlBgNVBAMMHkhBUklDQSBDbGllbnQg +UlNBIFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AIHbV0KQLHQ19Pi4dBlNqwlad0WBc2KwNZ/40LczAIcTtparDlQSMAe8m7dI19EZ +g66O2KnxqQCEsIxenugMj1Rpv/bUCE8mcP4YQWMaszKLQPgHq1cx8MYWdmeatN0v +8tFrxdCShJFxbg8uY+kfU6TdUhPMCYMpgQzFU3VEsQ5nUxjQwx+IS5+UJLQpvLvo +Tv1v0hUdSdyNcPIRGiBRVRG6iG/E91B51qox4oQ9XjLIdypQceULL+m26u+rCjM5 +Dv2PpWdDgo6YaQkJG0DNOGdH6snsl3ES3iT1cjzR90NMJveQsonpRUtVPTEFekHi +lbpDwBfFtoU9GY1kcPNbrM2f0yl1h0uVZ2qm+NHdvJCGiUMpqTdb9V2wJlpTQnaQ +K8+eVmwrVM9cmmXfW4tIYDh8+8ULz3YEYwIzKn31g2fn+sZD/SsP1CYvd6QywSTq +ZJ2/szhxMUTyR7iiZkGh+5t7vMdGanW/WqKM6GpEwbiWtcAyCC17dDVzssrG/q8R +chj258jCz6Uq6nvWWeh8oLJqQAlpDqWW29EAufGIbjbwiLKd8VLyw3y/MIk8Cmn5 +IqRl4ZvgdMaxhZeWLK6Uj1CmORIfvkfygXjTdTaefVogl+JSrpmfxnybZvP+2M/u +vZcGHS2F3D42U5Z7ILroyOGtlmI+EXyzAISep0xxq0o3AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFKDWBz1eJPd7oEQuJFINGaorBJGnMA4GA1Ud +DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEADUf5CWYxUux57sKo8mg+7ZZF +yzqmmGM/6itNTgPQHILhy9Pl1qtbZyi8nf4MmQqAVafOGyNhDbBX8P7gyr7mkNuD +LL6DjvR5tv7QDUKnWB9p6oH1BaX+RmjrbHjJ4Orn5t4xxdLVLIJjKJ1dqBp+iObn +K/Es1dAFntwtvTdm1ASip62/OsKoO63/jZ0z4LmahKGHH3b0gnTXDvkwSD5biD6q +XGvWLwzojnPCGJGDObZmWtAfYCddTeP2Og1mUJx4e6vzExCuDy+r6GSzGCCdRjVk +JXPqmxBcWDWJsUZIp/Ss1B2eW8yppRoTTyRQqtkbbbFA+53dWHTEwm8UcuzbNZ+4 +VHVFw6bIGig1Oq5l8qmYzq9byTiMMTt/zNyW/eJb1tBZ9Ha6C8tPgxDHQNAdYOkq +5UhYdwxFab4ZcQQk4uMkH0rIwT6Z9ZaYOEgloRWwG9fihBhb9nE1mmh7QMwYXAwk +ndSV9ZmqRuqurL/0FBkk6Izs4/W8BmiKKgwFXwqXdafcfsD913oY3zDROEsfsJhw +v8x8c/BuxDGlpJcdrL/ObCFKvicjZ/MGVoEKkY624QMFMyzaNAhNTlAjrR+lxdR6 +/uoJ7KcoYItGfLXqm91P+edrFcaIz0Pb5SfcBFZub0YV8VYt6FwMc8MjgTggy8kM +ac8sqzuEYDMZUv1pFDM= +-----END CERTIFICATE-----'`)) + + // HARICA TLS ECC Root CA 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE-----'`)) + + // HARICA TLS RSA Root CA 2021 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE-----'`)) + + // Hellenic Academic and Research Institutions ECC RootCA 2015 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE-----'`)) + + // Hellenic Academic and Research Institutions RootCA 2015 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE-----'`)) + + // IdenTrust Commercial Root CA 1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE-----'`)) + + // IdenTrust Public Sector Root CA 1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE-----'`)) + + // ISRG Root X1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE-----'`)) + + // ISRG Root X2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE-----'`)) + + // Izenpe.com + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE-----'`)) + + // SZAFIR ROOT CA2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE-----'`)) + + // LAWtrust Root CA2 (4096) + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFmDCCA4CgAwIBAgIEVRpusTANBgkqhkiG9w0BAQsFADBDMQswCQYDVQQGEwJa +QTERMA8GA1UEChMITEFXdHJ1c3QxITAfBgNVBAMTGExBV3RydXN0IFJvb3QgQ0Ey +ICg0MDk2KTAgFw0yMzAyMTQwOTE5MzhaGA8yMDUzMDIxNDA5NDkzOFowQzELMAkG +A1UEBhMCWkExETAPBgNVBAoTCExBV3RydXN0MSEwHwYDVQQDExhMQVd0cnVzdCBS +b290IENBMiAoNDA5NikwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +F8srQ7ps+cmTimUNEkzsJxS3E3ng1NUtGFbx+eoqEBZObETHamVG85qJNdGH+DOJ +L4gJGpIQkZDBa58Obn8mihNdGKxoAQ0QeGVw2I6PhFqXMBjQEQ5KjVIQpYErUSj1 +Y8S27ECzAeWtd73lOO+8jbPdGaB7DY2022r7JTNa+pGvxHFFMPiIKXvLv9W6JwSO +3bIA98pcmTUU6v11BhUIu8pXaPs/+7Q0c2PR1ePIOFppfWp6RAwNik7tkh0Qjzsi +LLbf7cXG8Il5VGVeXxu9j33fubft6+TFB9FnPJU7kf5CelJAgATSOVdL9JJ9/5vv +5Z3JCbKREjimKQg7ruvKzO1N504hAQf8bzLOaYyEUsZ36icwCt6lrzAraB+s1Owh +rSJJds4PwvIHKvlqEoOaOwSuGXr+oYYk+kFeJXxArCe24yk2bzXiV9AZWN//ZPbD +AUl22yu+vLlPFArVG1gh9hwuAHz4lLXLNxoU5DK5FtRg7AWqXzL6aiMSrNQQu9Ki +grRLDotwJ6rWB8FniPqEwwjJioTI0jdygQ+NFkrk1zVRpTgPjIRLlTbA9ded4F2P +q5HuAAi5nVIf7PiZu3lWsUna0uXYYYtbr/CrN8V7Go6Gvn7FexUeYWjoC4eLc0mh +F3N+KXiOyuBBL3VzdKKXOn/3LnQJuExgi0Y2GRAtnQIDAQABo4GRMIGOMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMCsGA1UdEAQkMCKADzIwMjMwMjE0 +MDkxOTM4WoEPMjA1MzAyMTQwOTQ5MzhaMB8GA1UdIwQYMBaAFNfWVmJcPxeB5nNE +KfVRBe8LYDesMB0GA1UdDgQWBBTX1lZiXD8XgeZzRCn1UQXvC2A3rDANBgkqhkiG +9w0BAQsFAAOCAgEASZwp/j3snkV/qz48/iNvNz53p1P/eJ/8SUSAV2acbtp5/81F +rUyTv7VZxukQt+X4jPuHxR6L2LM/ApYKu4qO79e0wIMgOJdZRWT89ncT8gnXocg4 +dAjq+UhM+h8EnLT/7G5WNnKTbJU+LF/eDwurycwVPhaPZvyyELih0bTewGMZzO9T +qnU2IoslH7+byNfBX+ymNwmqe2K89iIt8dZY3Yy7UvQLp3apensajdytmoFiLoYF +kHJHL6HJZ4SwDWywuJsWt9CZFC+cEpsjqI2mQx7p5S3leKcfZJRktneyqFz7Casp +6x5tddH20MWlwx2fHvMaLbLIH+UoCm7zX/3a5iOhdpBcS5gBgizuRy0CGl9/NMVp +tXKtPvPPnm34KegRJyvgWQsbYetKymmlpNXNURuUjnnN3/audF2xLBuGU/7RMAZB +NAdigkz0fseHdA6wIR4JIIDBsxU9Rm3T8QaSP++glYocbncxtut4KQx77oKlT36k +KV6eqi34jsDz/A0GhZtO3PfiCXzQFFEeerMjr/rRYSpltQHZuOMHyiR20vBKvu+G +BIBCFXARaH7Xx7v+506bnJWlHEqkydAJjKrOSNIekpfXEentZsw33PXXG3SbpupC +rF0y4Fj0gUf/0hLifhzcSXaWwx2fS8pcKjdbPYrROJsh2uO/RUPT4Fh3Hyg= +-----END CERTIFICATE-----'`)) + + // e-Szigno Root CA 2017 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE-----'`)) + + // Microsec e-Szigno Root CA 2009 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE-----'`)) + + // Microsoft ECC Root Certificate Authority 2017 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE-----'`)) + + // Microsoft RSA Root Certificate Authority 2017 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE-----'`)) + + // NAVER Global Root Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE-----'`)) + + // NetLock Arany (Class Gold) Főtanúsítvány + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE-----'`)) + + // OISTE WISeKey Global Root GA CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE-----'`)) + + // OISTE WISeKey Global Root GB CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE-----'`)) + + // OISTE WISeKey Global Root GC CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE-----'`)) + + // QuoVadis Root CA 1 G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE-----'`)) + + // QuoVadis Root CA 2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE-----'`)) + + // QuoVadis Root CA 2 G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE-----'`)) + + // QuoVadis Root CA 3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE-----'`)) + + // QuoVadis Root CA 3 G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE-----'`)) + + // Security Communication ECC RootCA1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT +AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD +VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx +NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT +HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 +IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl +dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK +ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu +9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O +be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= +-----END CERTIFICATE-----'`)) + + // Security Communication RootCA2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE-----'`)) + + // AAA Certificate Services + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE-----'`)) + + // COMODO Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE-----'`)) + + // COMODO ECC Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE-----'`)) + + // COMODO RSA Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE-----'`)) + + // Sectigo Public Email Protection Root E46 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICMTCCAbegAwIBAgIQbvXTp0GOoFlApzBr0kBlVjAKBggqhkjOPQQDAzBaMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTEwLwYDVQQDEyhT +ZWN0aWdvIFB1YmxpYyBFbWFpbCBQcm90ZWN0aW9uIFJvb3QgRTQ2MB4XDTIxMDMy +MjAwMDAwMFoXDTQ2MDMyMTIzNTk1OVowWjELMAkGA1UEBhMCR0IxGDAWBgNVBAoT +D1NlY3RpZ28gTGltaXRlZDExMC8GA1UEAxMoU2VjdGlnbyBQdWJsaWMgRW1haWwg +UHJvdGVjdGlvbiBSb290IEU0NjB2MBAGByqGSM49AgEGBSuBBAAiA2IABLinUpT1 +PgWwG/YfsdN+ueQFZlSAzmylaH3kU1LbgvrEht9DePfIrRa8P3gyy2vTSdZE5bN+ +n3umxizy4rbTibCaPEvOiUvGxss6SWAPRrxtTnqcyZuFewq2sEfCiOPU0aNCMEAw +HQYDVR0OBBYEFC1OjKfCI7JXqQZrPmsrifPDXkfOMA4GA1UdDwEB/wQEAwIBhjAP +BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCSnRpZY0VYjhsW5H16 +bDZIMB8rcueQMzT9JKLGBoxvOzJXWvj+xkkSU5rZELKZUXICMAUlKjMh/JPmIqLM +cFUoNVaiB8QhhCMaTEyZUJmSFMtK3Fb79dOPaiz1cTr4izsDng== +-----END CERTIFICATE-----'`)) + + // Sectigo Public Email Protection Root R46 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIQHUSeuQ2DkXSu3fLriLemozANBgkqhkiG9w0BAQwFADBa +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTEwLwYDVQQD +EyhTZWN0aWdvIFB1YmxpYyBFbWFpbCBQcm90ZWN0aW9uIFJvb3QgUjQ2MB4XDTIx +MDMyMjAwMDAwMFoXDTQ2MDMyMTIzNTk1OVowWjELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1NlY3RpZ28gTGltaXRlZDExMC8GA1UEAxMoU2VjdGlnbyBQdWJsaWMgRW1h +aWwgUHJvdGVjdGlvbiBSb290IFI0NjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAJHlG/qqbTcrdccuXxSl2yyXtixGj2nZ7JYt8x1avtMdI+ZoCf9KEXMa +rmefdprS5+y42V8r+SZWUa92nan8F+8yCtAjPLosT0eD7J0FaEJeBuDV6CtoSJey ++vOkcTV9NJsXi39NDdvcTwVMlGK/NfovyKccZtlxX+XmWlXKq/S4dxlFUEVOSqvb +nmbBGbc3QshWpUAS+TPoOEU6xoSjAo4vJLDDQYUHSZzP3NHyJm/tMxwzZypFN9mF +ZSIasbUQUglrA8YfcD2RxH2QPe1m+JD/JeDtkqKLMSmtnBJmeGOdV+z7C96O3IvL +Oql39Lrl7DiMi+YTZqdpWMOCGhrN8Z/YU5JOSX2pRefxQyFatz5AzWOJz9m/x1AL +4bzniJatntQX2l3P4JH9phDUuQOBm2ms+4SogTXrG+tobHxgPsPfybSudB1Ird1u +EYbhKmo2Fq7IzrzbWPxAk0DYjlOXwqwiOOWIMbMuoe/s4EIN6v+TVkoGpJtMAmhk +j1ZQwYEF/cvbxdcV8mu1dsOj+TLOyrVKqRt9Gdx/x2p+ley2uI39lUqcoytti/Fw +5UcrAFzkuZ7U+NlYKdDL4ChibK6cYuLMvDaTQfXv/kZilbBXSnQsR1Ipnd2ioU9C +wpLOLVBSXowKoffYncX4/TaHTlf9aKFfmYMc8LXd6JLTZUBVypaFAgMBAAGjQjBA +MB0GA1UdDgQWBBSn15V360rDJ82TvjdMJoQhFH1dmDAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQwFAAOCAgEANNLxFfOTAdRyi/Cr +CB8TPHO0sKvoeNlsupqvJuwQgOUNUzHd4/qMUSIkMze4GH46+ljoNOWM4KEfCUHS +Nz/Mywk1Qojp/BHXz0KqpHC2ccFTvcV0r8QiJGPPYoJ9yctRwYiQbVtcvvuZqLq2 +hrDpZgvlG2uv6iuGp9+oI0yWP09XQhgVg0Pxhia3KgPOC53opWgejG+9heMbUY/n +Fy8r0NZ4wi3dcojUZZ76mdR+55cKkgGapamEOgwqdD0zGMiH9+ik9YZCOf1rdSn8 +AAasoqUaVI7pUEkXZq9LBC2blIClVKuMVxdEnw/WaGRytEseAcfZm5TZg5mvEgUR +o5gi0vJXyiT5ujgVEki6Yzv8i5V41nIHVszN/J0c0MVkO2M0zwSZircweXq28sbV +2VR6hwt+TveE7BTziBYS8dWuChoJ7oat5av9rsMpeXTDAV8Rm991mcZK95uPbEns +IS+0AlmzLdBykLoLFHR4S8/BX1VyjlQrE876WAzTuyzZqZFh+PjxtnvevKnMkgTM +S2tfc4C2Ie1QT9d2h27O39K3vWKhfVhiaEVStj/eEtvtBGmedoiqAW3ahsdgG8NS +rDfsUHGAciohRQpTRzwZ643SWQTeJbDrHzVvYH3Xtca7CyeN4E1U5c8dJgFuOzXI +IBKJg/DS7Vg7NJ27MfUy/THzVho= +-----END CERTIFICATE-----'`)) + + // Sectigo Public Server Authentication Root E46 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN +MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG +A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC +WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ +6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B +Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa +qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q +4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== +-----END CERTIFICATE-----'`)) + + // Sectigo Public Server Authentication Root R46 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa +ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz +SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf +iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X +ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 +IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS +VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE +SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu ++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt +8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L +HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt +zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P +AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ +YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 +gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA +Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB +JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX +DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui +TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 +dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 +LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp +0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY +QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE-----'`)) + + // USERTrust ECC Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE-----'`)) + + // USERTrust RSA Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE-----'`)) + + // SSL.com Client ECC Root CA 2022 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICQDCCAcagAwIBAgIQdvhIHq7wPHAf4D8lVAGD1TAKBggqhkjOPQQDAzBRMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQDDB9T +U0wuY29tIENsaWVudCBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzAzMloX +DTQ2MDgxOTE2MzAzMVowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBDbGllbnQgRUNDIFJvb3QgQ0EgMjAy +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABC1Tfp+LPrM2ulDizOvcuiaK04wGP2cP +7/UX5dSumkYqQQEHaedncfHCAzbG8CtSjs8UkmikPnBREmmNeKKCyikUwOSUIrJE +kmBvyASkZ9Wi0PPQ1+qOPA+60kBHkDTufaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAf +BgNVHSMEGDAWgBS3/i1ixYFTzVIaL11goMNd+7IcHDAdBgNVHQ4EFgQUt/4tYsWB +U81SGi9dYKDDXfuyHBwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUC +ME0HES0R+7kmwyHdcuEX/MHPFOpJznGHjtZT3BHNXVSKr9kt9IxR6rxmR+J/lYNg +ZQIxAIwhTE+75bBQ35BiSebMkdv4P11xkQiOT5LJf6Zc6hN+7W3E6MMqb1wR4aXz +alqaTQ== +-----END CERTIFICATE-----'`)) + + // SSL.com Client RSA Root CA 2022 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFjzCCA3egAwIBAgIQdq/uiJMVRbZQU5uAnKTfmjANBgkqhkiG9w0BAQsFADBR +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQD +DB9TU0wuY29tIENsaWVudCBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzEw +N1oXDTQ2MDgxOTE2MzEwNlowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBD +b3Jwb3JhdGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBDbGllbnQgUlNBIFJvb3QgQ0Eg +MjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALhY20Yw+8k/48jw +ATM04tpIqBjpIG6a1wHh1SmPMLQjauTLYrC+4p8gvT5UoDlox4Y3ZnQGBu90K9rc +n4SpUi+Q0u5+fPulIq1vcEZnlj0p1KO7VnsUBFnBIWNEHrIfElyQh2UNiPYeiCLi +Y1S78zb41n/c2v8pNanGbg5pWz/YvoKHFXBdsMdcEg9jpjjNz3O5ww6JJjcbP2Ic +MmnRm9n/VZAx3rFj3c/FdHf874ghU78AMRomLAAwpV9s4+T2AIrKmIecdAN6i2bs +fv2jjzUlXHils6T7PW2pivBsiIKL/UrQb+TXo7SONEk4vs5F5dIcyl7CNxSLzWZW +Mzed5WvsQ5JkoELadW/AFez5ab00uYp7+hb7Vf5SIOgEBFZWZfU3RJjIikbpt6y4 +6L5ijlQ2W/c7cL9d7i26X95CGYbwf4vrCMvYvuoOQkKgNnNXF+0y6tCN6Acbm5no +xJpiBA5I9zwSuvdYwZqM6cewIzZWNB3LbNq6B4Qd/dGsn+bCie/DuWwYs2mHV1+1 +DDhbpyEkKjunNJGetFTqKE/TwaOL5OYr1fKdv5thACLd1ktEHz9dVv7enHjMmVuq +5L2620NLrUwmTKNNNIpsdDYT22L8m7IFgf+uPwzN9hui9DnnyvVMXPtUdzWAWsAS +oRMBM2c9nYGhqfWFJFiIeOf042hVAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAU8DhClDSpPAB/Uu45pfdLDbxqfSMwHQYDVR0OBBYEFPA4QpQ0 +qTwAf1LuOaX3Sw28an0jMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC +AgEAmU/b8OrWEfoq/cirbeQOc2LSQp8V/nxwUj9kh4IxP0VALuEinwZmKfyW0y2N +tjjH2fMnwVkpoIz2cyQPKCLXTmHdE93bnzJSk/tPzOo4PJhqA6sWryHRQq59RSvq +xM+KWZ+CcHY6+GImyRCXWEAkpC25LymAJ+GJa3LKSQhxN1MF8YDO00IC0vzC0ZQG +7gfi9oPif5/nu1bDW7/dlZMJHiTBzybNraSuwrRp56q17TeU6d3RY4VrmnpKVnbc +GYUo1OTGpNi4lkF30LRZ8UYFh4cCH2m5ghjQQ9km2hpnqNZ1durybQ5C/4gmom6E +/n5iG/DGPe3AHGrHkda4ADdJm7mEBaHNbjHWROpTi7pTmB2hkIrphfgb8pNYw8jc +miZPPiDPT0PzEIx/EGF6NsqqC33Mn0dEWa6llcaZU+MHaz1JELAY/10OhUMUS+dr +00q1smBh3GlJAiNd6JJxw5yfRWd5HtwyhrqqVTxkbzK1EEAV3nJAeOBucLtu6wno +OdmsupJ13UPKugGVrRqBKzrw48UvDBhNEMauwO3+BVJ/GQXLqa81CAw4IuT+VuVT +Pr/k1rPZCMM91TMygSTFqeFlEbgyMzBxGEkdGkXGmhSKWDkobvPLUblJJmR4A8eR +EYOpuZA0tm+qBZ6FKFeZvn8nBkliTaH8CeErRglMFJtWj0U= +-----END CERTIFICATE-----'`)) + + // SSL.com EV Root Certification Authority ECC + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE-----'`)) + + // SSL.com EV Root Certification Authority RSA R2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE-----'`)) + + // SSL.com Root Certification Authority ECC + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE-----'`)) + + // SSL.com Root Certification Authority RSA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE-----'`)) + + // SSL.com TLS ECC Root CA 2022 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== +-----END CERTIFICATE-----'`)) + + // SSL.com TLS RSA Root CA 2022 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE-----'`)) + + // SwissSign Gold CA - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE-----'`)) + + // SwissSign Silver CA - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE-----'`)) + + // TWCA CYBER Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ +MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 +IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 +WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO +LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P +40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF +avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/ +34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i +JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu +j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf +Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP +2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA +S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA +oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC +kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW +5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd +BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t +tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn +68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn +TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t +RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx +f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI +Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz +8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4 +NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX +xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 +t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE-----'`)) + + // TWCA Global Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE-----'`)) + + // TWCA Global Root CA G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFlTCCA32gAwIBAgIQQAE0jMIAAAAAAAAAAZdY9DANBgkqhkiG9w0BAQwFADBU +MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 +IENBMR8wHQYDVQQDExZUV0NBIEdsb2JhbCBSb290IENBIEcyMB4XDTIyMTEyMjA2 +NDIyMVoXDTQ3MTEyMjE1NTk1OVowVDELMAkGA1UEBhMCVFcxEjAQBgNVBAoTCVRB +SVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEfMB0GA1UEAxMWVFdDQSBHbG9iYWwg +Um9vdCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKoO1SCS +Aa2C+QwIkTRrihbQRhb/A7jYjeqTNPv/K739bqrcm/KGgVX1iRzEjXVqWHiREx4C +E3A9774K5wCPuDHldMUwvv991pnlwkKjzyHWswh/kdVh5qKVEA3vXpcLSTjVIrDX +i1lvnzWbf9KRzHp/u6Cf3lUz9kuNCup9CcB53L1E4v4c52QhKM8ESuK0v4Z5KrsO +k8mPXqwwOVKQB7nqnCZCFMRnRv7RGmihPlAZoyYKJymQwva063OaeB7hmPRlDDUh +BvgL3mLlTcGzXdm5+mGXKuPqx0RVJJL+Eqc/xHfgLQKBB9X7feYQnjq0qO/s+1Dq +Nc/MfrtCuURsUum/KnIfP96bcOncWsU7u7/wWYWvL8GwFHkFrHWfJfURJwZgIcdt +Zb6oiZzlrEbf+F1EA41gvfexDcwv70FUL+5rlblOfDTfO/l3nX3NBz0cBjMSgOxy +nPItgtrVO8TH+QTDZAJ89TVgp7RGKS4b76VYgC56iVE4Njz9oXe4gDDQit6NpzQm +7CO7GFUYNkXu7QEGqk2/ZAzKmJcaMQJm+HhoW4jfCajnm/o0bXAcIa0Ii/Khtqx2 +ar/xgCUAvjweTa65PLaVY71rfkcSkFVFEY3sFx/BvieBk1djaQAmd4vDWeV70Q1E +8qjw94WaBffCLnCak4XYlZAxkFSm7AufN0UPAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFJKM1DbRW0dTxHENhN1k +KvU2ZEDnMB0GA1UdDgQWBBSSjNQ20VtHU8RxDYTdZCr1NmRA5zANBgkqhkiG9w0B +AQwFAAOCAgEAJfxL2pC02nXnQTqB0ab+oGrzGHFiaiQIi6l6TclVzs8QKC4EGZYF +z10CICo7s1U/Ac1CzbJ37f9183x325alz4xnBvSkm3L2IUkJmKMyXndaYwnvYkOX +Aji16jwYUGj8WVvZedTx5FZIE1bY03ELXniUOBFF+gUX9Q51HmJSYUa6LhmthrSI +D7FQ5kAANBqVnZPgUfnUVUbplTwlhi6X1wExGETsHGDpfWmvMviXQCUkto0aVTzF +t/e8BlI7cTBwPnEXfvFmBF5dvIoxQ6aSHXtU0qU2i2+N1l7a1MMuHd85VWCCMJ4n +/46A3WNMplU12NAzqYBtPl6dzKhngGb6mVcMUsoZdbA4NVUqgcWMHlbXX5DyINja +4GZx6bJ4q2e5JG5rNnL8b439f3I5KGdSkQUfV2XSo6cNYfqh59U1RpXJBof2MOwy +UamsVsAhTqMUdAU6vOO/bT1OP16lpG0pv4RRdVOOhhr1UXAqDRxOQOH9o+OlK2eQ +ksdsroW/OpsXFcqcKpPUTTkNvCAIo42IbAkNjK5EIU3JcezYJtcXni0RGDyjIn24 +J1S/aMg7QsyPXk7n3MLF+mpED41WiHrfiYRsoLM+PfFlAAmI6irrQM6zXawyF67B +m+nQwfVJlN2nznxaB+uuIJwXMJJpk3Lzmltxm/5q33owaY6zLtsPLN0= +-----END CERTIFICATE-----'`)) + + // TWCA Root Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE-----'`)) + + // Telia Root CA v2 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE-----'`)) + + // TeliaSonera Root CA v1 + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE-----'`)) + + // Secure Global CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE-----'`)) + + // SecureTrust CA + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE-----'`)) + + // Trustwave Global Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE-----'`)) + + // Trustwave Global ECC P256 Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE-----'`)) + + // Trustwave Global ECC P384 Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE-----'`)) + + // XRamp Global Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE-----'`)) +} diff --git a/common/certificate/store.go b/common/certificate/store.go new file mode 100644 index 00000000..34f20019 --- /dev/null +++ b/common/certificate/store.go @@ -0,0 +1,185 @@ +package certificate + +import ( + "context" + "crypto/x509" + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/sagernet/fswatch" + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/libbox/platform" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + "github.com/sagernet/sing/service" +) + +var _ adapter.CertificateStore = (*Store)(nil) + +type Store struct { + systemPool *x509.CertPool + currentPool *x509.CertPool + certificate string + certificatePaths []string + certificateDirectoryPaths []string + watcher *fswatch.Watcher +} + +func NewStore(ctx context.Context, logger logger.Logger, options option.CertificateOptions) (*Store, error) { + var systemPool *x509.CertPool + switch options.Store { + case C.CertificateStoreSystem, "": + systemPool = x509.NewCertPool() + platformInterface := service.FromContext[platform.Interface](ctx) + var systemValid bool + if platformInterface != nil { + for _, cert := range platformInterface.SystemCertificates() { + if systemPool.AppendCertsFromPEM([]byte(cert)) { + systemValid = true + } + } + } + if !systemValid { + certPool, err := x509.SystemCertPool() + if err != nil { + return nil, err + } + systemPool = certPool + } + case C.CertificateStoreMozilla: + systemPool = mozillaIncluded + case C.CertificateStoreNone: + systemPool = nil + default: + return nil, E.New("unknown certificate store: ", options.Store) + } + store := &Store{ + systemPool: systemPool, + certificate: strings.Join(options.Certificate, "\n"), + certificatePaths: options.CertificatePath, + certificateDirectoryPaths: options.CertificateDirectoryPath, + } + var watchPaths []string + for _, target := range options.CertificatePath { + watchPaths = append(watchPaths, target) + } + for _, target := range options.CertificateDirectoryPath { + watchPaths = append(watchPaths, target) + } + if len(watchPaths) > 0 { + watcher, err := fswatch.NewWatcher(fswatch.Options{ + Path: watchPaths, + Logger: logger, + Callback: func(_ string) { + err := store.update() + if err != nil { + logger.Error(E.Cause(err, "reload certificates")) + } + }, + }) + if err != nil { + return nil, E.Cause(err, "fswatch: create fsnotify watcher") + } + store.watcher = watcher + } + err := store.update() + if err != nil { + return nil, E.Cause(err, "initializing certificate store") + } + return store, nil +} + +func (s *Store) Name() string { + return "certificate" +} + +func (s *Store) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + if s.watcher != nil { + return s.watcher.Start() + } + return nil +} + +func (s *Store) Close() error { + if s.watcher != nil { + return s.watcher.Close() + } + return nil +} + +func (s *Store) Pool() *x509.CertPool { + return s.currentPool +} + +func (s *Store) update() error { + var currentPool *x509.CertPool + if s.systemPool == nil { + currentPool = x509.NewCertPool() + } else { + currentPool = s.systemPool.Clone() + } + if s.certificate != "" { + if !currentPool.AppendCertsFromPEM([]byte(s.certificate)) { + return E.New("invalid certificate PEM strings") + } + } + for _, path := range s.certificatePaths { + pemContent, err := os.ReadFile(path) + if err != nil { + return err + } + if !currentPool.AppendCertsFromPEM(pemContent) { + return E.New("invalid certificate PEM file: ", path) + } + } + var firstErr error + for _, directoryPath := range s.certificateDirectoryPaths { + directoryEntries, err := readUniqueDirectoryEntries(directoryPath) + if err != nil { + if firstErr == nil && !os.IsNotExist(err) { + firstErr = E.Cause(err, "invalid certificate directory: ", directoryPath) + } + continue + } + for _, directoryEntry := range directoryEntries { + pemContent, err := os.ReadFile(filepath.Join(directoryPath, directoryEntry.Name())) + if err == nil { + currentPool.AppendCertsFromPEM(pemContent) + } + } + } + if firstErr != nil { + return firstErr + } + s.currentPool = currentPool + return nil +} + +func readUniqueDirectoryEntries(dir string) ([]fs.DirEntry, error) { + files, err := os.ReadDir(dir) + if err != nil { + return nil, err + } + uniq := files[:0] + for _, f := range files { + if !isSameDirSymlink(f, dir) { + uniq = append(uniq, f) + } + } + return uniq, nil +} + +func isSameDirSymlink(f fs.DirEntry, dir string) bool { + if f.Type()&fs.ModeSymlink == 0 { + return false + } + target, err := os.Readlink(filepath.Join(dir, f.Name())) + return err == nil && !strings.Contains(target, "/") +} diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index fff1873d..80219350 100644 --- a/common/tls/ech_client.go +++ b/common/tls/ech_client.go @@ -100,6 +100,7 @@ func NewECHClient(ctx context.Context, serverAddress string, options option.Outb var tlsConfig cftls.Config tlsConfig.Time = ntp.TimeFuncFromContext(ctx) + tlsConfig.RootCAs = adapter.RootPoolFromContext(ctx) if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { diff --git a/common/tls/ech_server.go b/common/tls/ech_server.go index d41783fe..03f5d876 100644 --- a/common/tls/ech_server.go +++ b/common/tls/ech_server.go @@ -90,7 +90,7 @@ func (c *echServerConfig) startWatcher() error { Callback: func(path string) { err := c.credentialsUpdated(path) if err != nil { - c.logger.Error(E.Cause(err, "reload credentials from ", path)) + c.logger.Error(E.Cause(err, "reload credentials")) } }, }) diff --git a/common/tls/reality_client.go b/common/tls/reality_client.go index f9a11a0b..748567b5 100644 --- a/common/tls/reality_client.go +++ b/common/tls/reality_client.go @@ -27,9 +27,11 @@ import ( "time" "unsafe" + "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common/debug" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/ntp" aTLS "github.com/sagernet/sing/common/tls" utls "github.com/sagernet/utls" @@ -40,6 +42,7 @@ import ( var _ ConfigCompat = (*RealityClientConfig)(nil) type RealityClientConfig struct { + ctx context.Context uClient *UTLSClientConfig publicKey []byte shortID [8]byte @@ -70,7 +73,7 @@ func NewRealityClient(ctx context.Context, serverAddress string, options option. if decodedLen > 8 { return nil, E.New("invalid short_id") } - return &RealityClientConfig{uClient, publicKey, shortID}, nil + return &RealityClientConfig{ctx, uClient, publicKey, shortID}, nil } func (e *RealityClientConfig) ServerName() string { @@ -180,20 +183,24 @@ func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn } if !verifier.verified { - go realityClientFallback(uConn, e.uClient.ServerName(), e.uClient.id) + go realityClientFallback(e.ctx, uConn, e.uClient.ServerName(), e.uClient.id) return nil, E.New("reality verification failed") } return &realityClientConnWrapper{uConn}, nil } -func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { +func realityClientFallback(ctx context.Context, uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { defer uConn.Close() client := &http.Client{ Transport: &http2.Transport{ DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { return uConn, nil }, + TLSClientConfig: &tls.Config{ + Time: ntp.TimeFuncFromContext(ctx), + RootCAs: adapter.RootPoolFromContext(ctx), + }, }, } request, _ := http.NewRequest("GET", "https://"+serverName, nil) @@ -213,6 +220,7 @@ func (e *RealityClientConfig) SetSessionIDGenerator(generator func(clientHello [ func (e *RealityClientConfig) Clone() Config { return &RealityClientConfig{ + e.ctx, e.uClient.Clone().(*UTLSClientConfig), e.publicKey, e.shortID, diff --git a/common/tls/std_client.go b/common/tls/std_client.go index 7cd130a6..78f4e5cf 100644 --- a/common/tls/std_client.go +++ b/common/tls/std_client.go @@ -8,6 +8,7 @@ import ( "os" "strings" + "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/ntp" @@ -58,6 +59,7 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb var tlsConfig tls.Config tlsConfig.Time = ntp.TimeFuncFromContext(ctx) + tlsConfig.RootCAs = adapter.RootPoolFromContext(ctx) if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { diff --git a/common/tls/std_server.go b/common/tls/std_server.go index 1e01bc50..c8dcfbf5 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -99,7 +99,7 @@ func (c *STDServerConfig) startWatcher() error { Callback: func(path string) { err := c.certificateUpdated(path) if err != nil { - c.logger.Error(err) + c.logger.Error(E.Cause(err, "reload certificate")) } }, }) diff --git a/common/tls/utls_client.go b/common/tls/utls_client.go index 15103f05..fe8e4296 100644 --- a/common/tls/utls_client.go +++ b/common/tls/utls_client.go @@ -12,6 +12,7 @@ import ( "os" "strings" + "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/ntp" @@ -130,6 +131,7 @@ func NewUTLSClient(ctx context.Context, serverAddress string, options option.Out var tlsConfig utls.Config tlsConfig.Time = ntp.TimeFuncFromContext(ctx) + tlsConfig.RootCAs = adapter.RootPoolFromContext(ctx) if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { diff --git a/common/urltest/urltest.go b/common/urltest/urltest.go index 9efd0404..cfe1e532 100644 --- a/common/urltest/urltest.go +++ b/common/urltest/urltest.go @@ -2,32 +2,32 @@ package urltest import ( "context" + "crypto/tls" "net" "net/http" "net/url" "sync" "time" + "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing/common" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/ntp" ) -type History struct { - Time time.Time `json:"time"` - Delay uint16 `json:"delay"` -} +var _ adapter.URLTestHistoryStorage = (*HistoryStorage)(nil) type HistoryStorage struct { access sync.RWMutex - delayHistory map[string]*History + delayHistory map[string]*adapter.URLTestHistory updateHook chan<- struct{} } func NewHistoryStorage() *HistoryStorage { return &HistoryStorage{ - delayHistory: make(map[string]*History), + delayHistory: make(map[string]*adapter.URLTestHistory), } } @@ -35,7 +35,7 @@ func (s *HistoryStorage) SetHook(hook chan<- struct{}) { s.updateHook = hook } -func (s *HistoryStorage) LoadURLTestHistory(tag string) *History { +func (s *HistoryStorage) LoadURLTestHistory(tag string) *adapter.URLTestHistory { if s == nil { return nil } @@ -51,7 +51,7 @@ func (s *HistoryStorage) DeleteURLTestHistory(tag string) { s.notifyUpdated() } -func (s *HistoryStorage) StoreURLTestHistory(tag string, history *History) { +func (s *HistoryStorage) StoreURLTestHistory(tag string, history *adapter.URLTestHistory) { s.access.Lock() s.delayHistory[tag] = history s.access.Unlock() @@ -110,6 +110,10 @@ func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err e DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return instance, nil }, + TLSClientConfig: &tls.Config{ + Time: ntp.TimeFuncFromContext(ctx), + RootCAs: adapter.RootPoolFromContext(ctx), + }, }, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse diff --git a/constant/certificate.go b/constant/certificate.go new file mode 100644 index 00000000..7138242c --- /dev/null +++ b/constant/certificate.go @@ -0,0 +1,7 @@ +package constant + +const ( + CertificateStoreSystem = "system" + CertificateStoreMozilla = "mozilla" + CertificateStoreNone = "none" +) diff --git a/experimental/clashapi/api_meta_group.go b/experimental/clashapi/api_meta_group.go index 8f09ced9..31dbdaf6 100644 --- a/experimental/clashapi/api_meta_group.go +++ b/experimental/clashapi/api_meta_group.go @@ -111,7 +111,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request) server.urlTestHistory.DeleteURLTestHistory(realTag) } else { server.logger.Debug("outbound ", tag, " available: ", t, "ms") - server.urlTestHistory.StoreURLTestHistory(realTag, &urltest.History{ + server.urlTestHistory.StoreURLTestHistory(realTag, &adapter.URLTestHistory{ Time: time.Now(), Delay: t, }) diff --git a/experimental/clashapi/proxies.go b/experimental/clashapi/proxies.go index 6246b9da..ef88ff37 100644 --- a/experimental/clashapi/proxies.go +++ b/experimental/clashapi/proxies.go @@ -72,9 +72,9 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject { info.Put("udp", common.Contains(detour.Network(), N.NetworkUDP)) delayHistory := server.urlTestHistory.LoadURLTestHistory(adapter.OutboundTag(detour)) if delayHistory != nil { - info.Put("history", []*urltest.History{delayHistory}) + info.Put("history", []*adapter.URLTestHistory{delayHistory}) } else { - info.Put("history", []*urltest.History{}) + info.Put("history", []*adapter.URLTestHistory{}) } if group, isGroup := detour.(adapter.OutboundGroup); isGroup { info.Put("now", group.Now()) @@ -116,7 +116,7 @@ func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) { "type": "Fallback", "name": "GLOBAL", "udp": true, - "history": []*urltest.History{}, + "history": []*adapter.URLTestHistory{}, "all": allProxies, "now": defaultTag, }) @@ -208,7 +208,7 @@ func getProxyDelay(server *Server) func(w http.ResponseWriter, r *http.Request) if err != nil { server.urlTestHistory.DeleteURLTestHistory(realTag) } else { - server.urlTestHistory.StoreURLTestHistory(realTag, &urltest.History{ + server.urlTestHistory.StoreURLTestHistory(realTag, &adapter.URLTestHistory{ Time: time.Now(), Delay: delay, }) diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go index d01e180a..e6d8c4cf 100644 --- a/experimental/clashapi/server.go +++ b/experimental/clashapi/server.go @@ -48,7 +48,7 @@ type Server struct { logger log.Logger httpServer *http.Server trafficManager *trafficontrol.Manager - urlTestHistory *urltest.HistoryStorage + urlTestHistory adapter.URLTestHistoryStorage mode string modeList []string modeUpdateHook chan<- struct{} @@ -79,7 +79,7 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op externalUIDownloadURL: options.ExternalUIDownloadURL, externalUIDownloadDetour: options.ExternalUIDownloadDetour, } - s.urlTestHistory = service.PtrFromContext[urltest.HistoryStorage](ctx) + s.urlTestHistory = service.FromContext[adapter.URLTestHistoryStorage](ctx) if s.urlTestHistory == nil { s.urlTestHistory = urltest.NewHistoryStorage() } @@ -234,7 +234,7 @@ func (s *Server) SetMode(newMode string) { s.logger.Info("updated mode: ", newMode) } -func (s *Server) HistoryStorage() *urltest.HistoryStorage { +func (s *Server) HistoryStorage() adapter.URLTestHistoryStorage { return s.urlTestHistory } diff --git a/experimental/clashapi/server_resources.go b/experimental/clashapi/server_resources.go index ec3b2a0f..f480ebf0 100644 --- a/experimental/clashapi/server_resources.go +++ b/experimental/clashapi/server_resources.go @@ -3,6 +3,7 @@ package clashapi import ( "archive/zip" "context" + "crypto/tls" "io" "net" "net/http" @@ -15,6 +16,7 @@ import ( "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/ntp" "github.com/sagernet/sing/service/filemanager" ) @@ -60,6 +62,10 @@ func (s *Server) downloadExternalUI() error { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return detour.DialContext(ctx, network, M.ParseSocksaddr(addr)) }, + TLSClientConfig: &tls.Config{ + Time: ntp.TimeFuncFromContext(s.ctx), + RootCAs: adapter.RootPoolFromContext(s.ctx), + }, }, } defer httpClient.CloseIdleConnections() diff --git a/experimental/libbox/command_urltest.go b/experimental/libbox/command_urltest.go index c30d996e..5dcb3d67 100644 --- a/experimental/libbox/command_urltest.go +++ b/experimental/libbox/command_urltest.go @@ -76,7 +76,7 @@ func (s *CommandServer) handleURLTest(conn net.Conn) error { if err != nil { historyStorage.DeleteURLTestHistory(outboundTag) } else { - historyStorage.StoreURLTestHistory(outboundTag, &urltest.History{ + historyStorage.StoreURLTestHistory(outboundTag, &adapter.URLTestHistory{ Time: time.Now(), Delay: t, }) diff --git a/experimental/libbox/config.go b/experimental/libbox/config.go index 603d8b6d..d3149dc2 100644 --- a/experimental/libbox/config.go +++ b/experimental/libbox/config.go @@ -108,6 +108,10 @@ func (s *platformInterfaceStub) ReadWIFIState() adapter.WIFIState { return adapter.WIFIState{} } +func (s *platformInterfaceStub) SystemCertificates() []string { + return nil +} + func (s *platformInterfaceStub) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*process.Info, error) { return nil, os.ErrInvalid } diff --git a/experimental/libbox/platform.go b/experimental/libbox/platform.go index f0590367..affcad38 100644 --- a/experimental/libbox/platform.go +++ b/experimental/libbox/platform.go @@ -21,6 +21,7 @@ type PlatformInterface interface { UnderNetworkExtension() bool IncludeAllNetworks() bool ReadWIFIState() *WIFIState + SystemCertificates() StringIterator ClearDNSCache() SendNotification(notification *Notification) error } diff --git a/experimental/libbox/platform/interface.go b/experimental/libbox/platform/interface.go index ef37daea..35b0830b 100644 --- a/experimental/libbox/platform/interface.go +++ b/experimental/libbox/platform/interface.go @@ -19,6 +19,7 @@ type Interface interface { IncludeAllNetworks() bool ClearDNSCache() ReadWIFIState() adapter.WIFIState + SystemCertificates() []string process.Searcher SendNotification(notification *Notification) error } diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index a1e2ec8e..00b36237 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -34,7 +34,7 @@ import ( type BoxService struct { ctx context.Context cancel context.CancelFunc - urlTestHistoryStorage *urltest.HistoryStorage + urlTestHistoryStorage adapter.URLTestHistoryStorage instance *box.Box clashServer adapter.ClashServer pauseManager pause.Manager @@ -233,6 +233,10 @@ func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState { return (adapter.WIFIState)(*wifiState) } +func (w *platformInterfaceWrapper) SystemCertificates() []string { + return iteratorToArray[string](w.iif.SystemCertificates()) +} + func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*process.Info, error) { var uid int32 if w.useProcFS { diff --git a/option/certificate.go b/option/certificate.go new file mode 100644 index 00000000..ab524b99 --- /dev/null +++ b/option/certificate.go @@ -0,0 +1,36 @@ +package option + +import ( + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing/common/json" + "github.com/sagernet/sing/common/json/badoption" +) + +type _CertificateOptions struct { + Store string `json:"store,omitempty"` + Certificate badoption.Listable[string] `json:"certificate,omitempty"` + CertificatePath badoption.Listable[string] `json:"certificate_path,omitempty"` + CertificateDirectoryPath badoption.Listable[string] `json:"certificate_directory_path,omitempty"` +} + +type CertificateOptions _CertificateOptions + +func (o CertificateOptions) MarshalJSON() ([]byte, error) { + switch o.Store { + case C.CertificateStoreSystem: + o.Store = "" + } + return json.Marshal((*_CertificateOptions)(&o)) +} + +func (o *CertificateOptions) UnmarshalJSON(data []byte) error { + err := json.Unmarshal(data, (*_CertificateOptions)(o)) + if err != nil { + return err + } + switch o.Store { + case C.CertificateStoreSystem, "": + o.Store = C.CertificateStoreSystem + } + return nil +} diff --git a/option/options.go b/option/options.go index 94c97719..168074ed 100644 --- a/option/options.go +++ b/option/options.go @@ -13,6 +13,7 @@ type _Options struct { Log *LogOptions `json:"log,omitempty"` DNS *DNSOptions `json:"dns,omitempty"` NTP *NTPOptions `json:"ntp,omitempty"` + Certificate *CertificateOptions `json:"certificate,omitempty"` Endpoints []Endpoint `json:"endpoints,omitempty"` Inbounds []Inbound `json:"inbounds,omitempty"` Outbounds []Outbound `json:"outbounds,omitempty"` diff --git a/protocol/group/urltest.go b/protocol/group/urltest.go index 564c2373..0ebdc1ca 100644 --- a/protocol/group/urltest.go +++ b/protocol/group/urltest.go @@ -187,7 +187,7 @@ type URLTestGroup struct { interval time.Duration tolerance uint16 idleTimeout time.Duration - history *urltest.HistoryStorage + history adapter.URLTestHistoryStorage checking atomic.Bool pauseManager pause.Manager selectedOutboundTCP adapter.Outbound @@ -215,8 +215,9 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage if interval > idleTimeout { return nil, E.New("interval must be less or equal than idle_timeout") } - var history *urltest.HistoryStorage - if history = service.PtrFromContext[urltest.HistoryStorage](ctx); history != nil { + var history adapter.URLTestHistoryStorage + if historyFromCtx := service.PtrFromContext[urltest.HistoryStorage](ctx); historyFromCtx != nil { + history = historyFromCtx } else if clashServer := service.FromContext[adapter.ClashServer](ctx); clashServer != nil { history = clashServer.HistoryStorage() } else { @@ -379,7 +380,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint g.history.DeleteURLTestHistory(realTag) } else { g.logger.Debug("outbound ", tag, " available: ", t, "ms") - g.history.StoreURLTestHistory(realTag, &urltest.History{ + g.history.StoreURLTestHistory(realTag, &adapter.URLTestHistory{ Time: time.Now(), Delay: t, }) diff --git a/route/router.go b/route/router.go index 63fc7b10..89610445 100644 --- a/route/router.go +++ b/route/router.go @@ -90,7 +90,7 @@ func (r *Router) Start(stage adapter.StartStage) error { var cacheContext *adapter.HTTPStartContext if len(r.ruleSets) > 0 { monitor.Start("initialize rule-set") - cacheContext = adapter.NewHTTPStartContext() + cacheContext = adapter.NewHTTPStartContext(r.ctx) var ruleSetStartGroup task.Group for i, ruleSet := range r.ruleSets { ruleSetInPlace := ruleSet diff --git a/route/rule/rule_set_remote.go b/route/rule/rule_set_remote.go index 9e0c1729..8e89285b 100644 --- a/route/rule/rule_set_remote.go +++ b/route/rule/rule_set_remote.go @@ -3,6 +3,7 @@ package rule import ( "bytes" "context" + "crypto/tls" "io" "net" "net/http" @@ -23,6 +24,7 @@ import ( "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/ntp" "github.com/sagernet/sing/common/x/list" "github.com/sagernet/sing/service" "github.com/sagernet/sing/service/pause" @@ -235,6 +237,10 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTT DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return s.dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) }, + TLSClientConfig: &tls.Config{ + Time: ntp.TimeFuncFromContext(s.ctx), + RootCAs: adapter.RootPoolFromContext(s.ctx), + }, }, } } From 05f3df59b0c3497e7a8d8d7be7f40683832b1104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 25 Jan 2025 20:35:10 +0800 Subject: [PATCH 41/62] documentation: Refactor DNS --- docs/configuration/dns/fakeip.md | 8 + docs/configuration/dns/fakeip.zh.md | 8 + docs/configuration/dns/index.md | 2 - docs/configuration/dns/index.zh.md | 2 - docs/configuration/dns/rule_action.md | 11 + docs/configuration/dns/rule_action.zh.md | 14 +- docs/configuration/dns/server/dhcp.md | 38 ++ docs/configuration/dns/server/fakeip.md | 35 ++ docs/configuration/dns/server/http3.md | 71 +++ docs/configuration/dns/server/https.md | 71 +++ docs/configuration/dns/server/index.md | 46 ++ .../dns/{server.md => server/legacy.md} | 8 + .../dns/{server.zh.md => server/legacy.zh.md} | 8 + docs/configuration/dns/server/local.md | 33 ++ docs/configuration/dns/server/predefined.md | 93 ++++ docs/configuration/dns/server/quic.md | 58 ++ docs/configuration/dns/server/tcp.md | 52 ++ docs/configuration/dns/server/tls.md | 58 ++ docs/configuration/dns/server/udp.md | 52 ++ docs/deprecated.md | 9 + docs/deprecated.zh.md | 7 + docs/migration.md | 509 +++++++++++++++++ docs/migration.zh.md | 511 +++++++++++++++++- mkdocs.yml | 14 +- 24 files changed, 1710 insertions(+), 8 deletions(-) create mode 100644 docs/configuration/dns/server/dhcp.md create mode 100644 docs/configuration/dns/server/fakeip.md create mode 100644 docs/configuration/dns/server/http3.md create mode 100644 docs/configuration/dns/server/https.md create mode 100644 docs/configuration/dns/server/index.md rename docs/configuration/dns/{server.md => server/legacy.md} (93%) rename docs/configuration/dns/{server.zh.md => server/legacy.zh.md} (92%) create mode 100644 docs/configuration/dns/server/local.md create mode 100644 docs/configuration/dns/server/predefined.md create mode 100644 docs/configuration/dns/server/quic.md create mode 100644 docs/configuration/dns/server/tcp.md create mode 100644 docs/configuration/dns/server/tls.md create mode 100644 docs/configuration/dns/server/udp.md diff --git a/docs/configuration/dns/fakeip.md b/docs/configuration/dns/fakeip.md index 63490ac1..f9204d34 100644 --- a/docs/configuration/dns/fakeip.md +++ b/docs/configuration/dns/fakeip.md @@ -1,3 +1,11 @@ +--- +icon: material/delete-clock +--- + +!!! failure "Deprecated in sing-box 1.12.0" + + Legacy fake-ip configuration is deprecated and will be removed in sing-box 1.14.0, check [Migration](/migration/#migrate-to-new-dns-servers). + ### Structure ```json diff --git a/docs/configuration/dns/fakeip.zh.md b/docs/configuration/dns/fakeip.zh.md index 10c6dc68..e4d77b35 100644 --- a/docs/configuration/dns/fakeip.zh.md +++ b/docs/configuration/dns/fakeip.zh.md @@ -1,3 +1,11 @@ +--- +icon: material/delete-clock +--- + +!!! failure "已在 sing-box 1.12.0 废弃" + + 旧的 fake-ip 配置已废弃且将在 sing-box 1.14.0 中被移除,参阅 [迁移指南](/migration/#migrate-to-new-dns-servers)。 + ### 结构 ```json diff --git a/docs/configuration/dns/index.md b/docs/configuration/dns/index.md index 0756281d..43c7d573 100644 --- a/docs/configuration/dns/index.md +++ b/docs/configuration/dns/index.md @@ -49,8 +49,6 @@ Default domain strategy for resolving the domain names. One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`. -Take no effect if `server.strategy` is set. - #### disable_cache Disable dns cache. diff --git a/docs/configuration/dns/index.zh.md b/docs/configuration/dns/index.zh.md index 76c07b6a..8ed6a854 100644 --- a/docs/configuration/dns/index.zh.md +++ b/docs/configuration/dns/index.zh.md @@ -48,8 +48,6 @@ icon: material/new-box 可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。 -如果设置了 `server.strategy`,则不生效。 - #### disable_cache 禁用 DNS 缓存。 diff --git a/docs/configuration/dns/rule_action.md b/docs/configuration/dns/rule_action.md index af19131f..c3f8c2cb 100644 --- a/docs/configuration/dns/rule_action.md +++ b/docs/configuration/dns/rule_action.md @@ -2,6 +2,10 @@ icon: material/new-box --- +!!! quote "Changes in sing-box 1.12.0" + + :material-plus: [strategy](#strategy) + !!! question "Since sing-box 1.11.0" ### route @@ -10,6 +14,7 @@ icon: material/new-box { "action": "route", // default "server": "", + "strategy": "", "disable_cache": false, "rewrite_ttl": 0, "client_subnet": null @@ -24,6 +29,12 @@ icon: material/new-box Tag of target server. +#### strategy + +Set domain strategy for this query. + +One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`. + #### disable_cache Disable cache and save cache in this query. diff --git a/docs/configuration/dns/rule_action.zh.md b/docs/configuration/dns/rule_action.zh.md index 219a5fd7..427f8a8d 100644 --- a/docs/configuration/dns/rule_action.zh.md +++ b/docs/configuration/dns/rule_action.zh.md @@ -2,6 +2,10 @@ icon: material/new-box --- +!!! quote "sing-box 1.12.0 中的更改" + + :material-plus: [strategy](#strategy) + !!! question "自 sing-box 1.11.0 起" ### route @@ -10,8 +14,8 @@ icon: material/new-box { "action": "route", // 默认 "server": "", - - // 兼容性 + + "strategy": "", "disable_cache": false, "rewrite_ttl": 0, "client_subnet": null @@ -26,6 +30,12 @@ icon: material/new-box 目标 DNS 服务器的标签。 +#### strategy + +为此查询设置域名策略。 + +可选项:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。 + #### disable_cache 在此查询中禁用缓存。 diff --git a/docs/configuration/dns/server/dhcp.md b/docs/configuration/dns/server/dhcp.md new file mode 100644 index 00000000..b26da2a5 --- /dev/null +++ b/docs/configuration/dns/server/dhcp.md @@ -0,0 +1,38 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# DHCP + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "dhcp", + "tag": "", + + "interface": "", + + // Dial Fields + } + ] + } +} +``` + +### Fields + +#### interface + +Interface name to listen on. + +Tge default interface will be used by default. + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/fakeip.md b/docs/configuration/dns/server/fakeip.md new file mode 100644 index 00000000..6d2bba43 --- /dev/null +++ b/docs/configuration/dns/server/fakeip.md @@ -0,0 +1,35 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# Fake IP + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "fakeip", + "tag": "", + + "inet4_range": "198.18.0.0/15", + "inet6_range": "fc00::/18" + } + ] + } +} +``` + +### Fields + +#### inet4_range + +IPv4 address range for FakeIP. + +#### inet6_address + +IPv6 address range for FakeIP. diff --git a/docs/configuration/dns/server/http3.md b/docs/configuration/dns/server/http3.md new file mode 100644 index 00000000..89f000e8 --- /dev/null +++ b/docs/configuration/dns/server/http3.md @@ -0,0 +1,71 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# DNS over HTTP3 (DoH3) + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "h3", + "tag": "", + + "server": "", + "server_port": 443, + + "path": "", + "headers": {}, + + "tls": {}, + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy H3 server" + + * The old server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + * The old server uses `address_resolver` and `address_strategy` to resolve the domain name in the server; the new one uses `domain_resolver` and `domain_strategy` in [Dial Fields](/configuration/shared/dial/) instead. + +### Fields + +#### server + +==Required== + +The address of the DNS server. + +If domain name is used, `domain_resolver` must also be set to resolve IP address. + +#### server_port + +The port of the DNS server. + +`853` will be used by default. + +#### path + +The path of the DNS server. + +`/dns-query` will be used by default. + +#### headers + +Additional headers to be sent to the DNS server. + +#### tls + +TLS configuration, see [TLS](/configuration/shared/tls/#outbound). + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/https.md b/docs/configuration/dns/server/https.md new file mode 100644 index 00000000..93dc71a4 --- /dev/null +++ b/docs/configuration/dns/server/https.md @@ -0,0 +1,71 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# DNS over HTTPS (DoH) + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "https", + "tag": "", + + "server": "", + "server_port": 443, + + "path": "", + "headers": {}, + + "tls": {}, + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy HTTPS server" + + * The old server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + * The old server uses `address_resolver` and `address_strategy` to resolve the domain name in the server; the new one uses `domain_resolver` and `domain_strategy` in [Dial Fields](/configuration/shared/dial/) instead. + +### Fields + +#### server + +==Required== + +The address of the DNS server. + +If domain name is used, `domain_resolver` must also be set to resolve IP address. + +#### server_port + +The port of the DNS server. + +`853` will be used by default. + +#### path + +The path of the DNS server. + +`/dns-query` will be used by default. + +#### headers + +Additional headers to be sent to the DNS server. + +#### tls + +TLS configuration, see [TLS](/configuration/shared/tls/#outbound). + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/index.md b/docs/configuration/dns/server/index.md new file mode 100644 index 00000000..5393b0bd --- /dev/null +++ b/docs/configuration/dns/server/index.md @@ -0,0 +1,46 @@ +--- +icon: material/alert-decagram +--- + +!!! quote "Changes in sing-box 1.12.0" + + :material-plus: [type](#type) + +# DNS Server + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "", + "tag": "" + } + ] + } +} +``` + +#### type + +The type of the DNS server. + +| Type | Format | +|-----------------|-----------------------------------------------------| +| empty (default) | [Legacy](/configuration/dns/server/legacy/) | +| `tcp` | [TCP](/configuration/dns/server/tcp/) | +| `udp` | [UDP](/configuration/dns/server/udp/) | +| `tls` | [TLS](/configuration/dns/server/tls/) | +| `https` | [HTTPS](/configuration/dns/server/https/) | +| `quic` | [QUIC](/configuration/dns/server/quic/) | +| `h3` | [HTTP/3](/configuration/dns/server/http3/) | +| `predefined` | [Predefined](/configuration/dns/server/predefined/) | +| `dhcp` | [DHCP](/configuration/dns/server/dhcp/) | +| `fakeip` | [Fake IP](/configuration/dns/server/fakeip/) | + + +#### tag + +The tag of the DNS server. diff --git a/docs/configuration/dns/server.md b/docs/configuration/dns/server/legacy.md similarity index 93% rename from docs/configuration/dns/server.md rename to docs/configuration/dns/server/legacy.md index 5ec75faa..387d76ec 100644 --- a/docs/configuration/dns/server.md +++ b/docs/configuration/dns/server/legacy.md @@ -1,3 +1,11 @@ +--- +icon: material/delete-clock +--- + +!!! failure "Deprecated in sing-box 1.12.0" + + Legacy DNS servers is deprecated and will be removed in sing-box 1.14.0, check [Migration](/migration/#migrate-to-new-dns-servers). + !!! quote "Changes in sing-box 1.9.0" :material-plus: [client_subnet](#client_subnet) diff --git a/docs/configuration/dns/server.zh.md b/docs/configuration/dns/server/legacy.zh.md similarity index 92% rename from docs/configuration/dns/server.zh.md rename to docs/configuration/dns/server/legacy.zh.md index 9f470541..4bf2bcd3 100644 --- a/docs/configuration/dns/server.zh.md +++ b/docs/configuration/dns/server/legacy.zh.md @@ -1,3 +1,11 @@ +--- +icon: material/delete-clock +--- + +!!! failure "Deprecated in sing-box 1.12.0" + + 旧的 DNS 服务器配置已废弃且将在 sing-box 1.14.0 中被移除,参阅 [迁移指南](/migration/#migrate-to-new-dns-servers)。 + !!! quote "sing-box 1.9.0 中的更改" :material-plus: [client_subnet](#client_subnet) diff --git a/docs/configuration/dns/server/local.md b/docs/configuration/dns/server/local.md new file mode 100644 index 00000000..debcba98 --- /dev/null +++ b/docs/configuration/dns/server/local.md @@ -0,0 +1,33 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# Local + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "local", + "tag": "", + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy local server" + + * The old legacy local server only handles IP requests; the new one handles all types of requests and supports concurrent for IP requests. + * The old local server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/predefined.md b/docs/configuration/dns/server/predefined.md new file mode 100644 index 00000000..ac75d6bb --- /dev/null +++ b/docs/configuration/dns/server/predefined.md @@ -0,0 +1,93 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# Predefined + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "predefined", + "tag": "", + "responses": [] + } + ] + } +} +``` + +### Fields + +#### responses + +==Required== + +List of [Response](#response-structure). + +### Response Structure + +```json +{ + "query": [], + "query_type": [], + "rcode": "", + "answer": [], + "ns": [], + "extra": [] +} +``` + +!!! note "" + + You can ignore the JSON Array [] tag when the content is only one item + +### Response Fields + +#### query + +List of domain name to match. + +#### query_type + +List of query type to match. + +#### rcode + +The response code. + +| Value | Value in the legacy rcode server | Description | +|------------|----------------------------------|-----------------| +| `NOERROR` | `success` | Ok | +| `FORMERR` | `format_error` | Bad request | +| `SERVFAIL` | `server_failure` | Server failure | +| `NXDOMAIN` | `name_error` | Not found | +| `NOTIMP` | `not_implemented` | Not implemented | +| `REFUSED` | `refused` | Refused | + +`NOERROR` will be used by default. + +#### answer + +List of text DNS record to respond as answers. + +Examples: + +| Record Type | Example | +|-------------|-------------------------------| +| `A` | `localhost. IN A 127.0.0.1` | +| `AAAA` | `localhost. IN AAAA ::1` | +| `TXT` | `localhost. IN TXT \"Hello\"` | + +#### ns + +List of text DNS record to respond as name servers. + +#### extra + +List of text DNS record to respond as extra records. diff --git a/docs/configuration/dns/server/quic.md b/docs/configuration/dns/server/quic.md new file mode 100644 index 00000000..096264fe --- /dev/null +++ b/docs/configuration/dns/server/quic.md @@ -0,0 +1,58 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# DNS over QUIC (DoQ) + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "quic", + "tag": "", + + "server": "", + "server_port": 853, + + "tls": {}, + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy QUIC server" + + * The old server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + * The old server uses `address_resolver` and `address_strategy` to resolve the domain name in the server; the new one uses `domain_resolver` and `domain_strategy` in [Dial Fields](/configuration/shared/dial/) instead. + +### Fields + +#### server + +==Required== + +The address of the DNS server. + +If domain name is used, `domain_resolver` must also be set to resolve IP address. + +#### server_port + +The port of the DNS server. + +`853` will be used by default. + +#### tls + +TLS configuration, see [TLS](/configuration/shared/tls/#outbound). + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/tcp.md b/docs/configuration/dns/server/tcp.md new file mode 100644 index 00000000..c0a4ceaf --- /dev/null +++ b/docs/configuration/dns/server/tcp.md @@ -0,0 +1,52 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# TCP + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "tcp", + "tag": "", + + "server": "", + "server_port": 53, + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy TCP server" + + * The old server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + * The old server uses `address_resolver` and `address_strategy` to resolve the domain name in the server; the new one uses `domain_resolver` and `domain_strategy` in [Dial Fields](/configuration/shared/dial/) instead. + +### Fields + +#### server + +==Required== + +The address of the DNS server. + +If domain name is used, `domain_resolver` must also be set to resolve IP address. + +#### server_port + +The port of the DNS server. + +`53` will be used by default. + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/tls.md b/docs/configuration/dns/server/tls.md new file mode 100644 index 00000000..0e3be226 --- /dev/null +++ b/docs/configuration/dns/server/tls.md @@ -0,0 +1,58 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# DNS over TLS (DoT) + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "tls", + "tag": "", + + "server": "", + "server_port": 853, + + "tls": {}, + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy TLS server" + + * The old server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + * The old server uses `address_resolver` and `address_strategy` to resolve the domain name in the server; the new one uses `domain_resolver` and `domain_strategy` in [Dial Fields](/configuration/shared/dial/) instead. + +### Fields + +#### server + +==Required== + +The address of the DNS server. + +If domain name is used, `domain_resolver` must also be set to resolve IP address. + +#### server_port + +The port of the DNS server. + +`853` will be used by default. + +#### tls + +TLS configuration, see [TLS](/configuration/shared/tls/#outbound). + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/dns/server/udp.md b/docs/configuration/dns/server/udp.md new file mode 100644 index 00000000..4ffbf4d8 --- /dev/null +++ b/docs/configuration/dns/server/udp.md @@ -0,0 +1,52 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# TCP + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "udp", + "tag": "", + + "server": "", + "server_port": 53, + + // Dial Fields + } + ] + } +} +``` + +!!! info "Difference from legacy UDP server" + + * The old server uses default outbound by default unless detour is specified; the new one uses dialer just like outbound, which is equivalent to using an empty direct outbound by default. + * The old server uses `address_resolver` and `address_strategy` to resolve the domain name in the server; the new one uses `domain_resolver` and `domain_strategy` in [Dial Fields](/configuration/shared/dial/) instead. + +### Fields + +#### server + +==Required== + +The address of the DNS server. + +If domain name is used, `domain_resolver` must also be set to resolve IP address. + +#### server_port + +The port of the DNS server. + +`53` will be used by default. + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/deprecated.md b/docs/deprecated.md index 1868d952..40bbc3a4 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -4,6 +4,15 @@ icon: material/delete-alert # Deprecated Feature List +## 1.12.0 + +#### Legacy DNS server formats + +DNS servers are refactored, +check [Migration](../migration/#migrate-to-new-dns-servers). + +Compatibility for old formats will be removed in sing-box 1.14.0. + ## 1.11.0 #### Legacy special outbounds diff --git a/docs/deprecated.zh.md b/docs/deprecated.zh.md index 2cda6386..29f38742 100644 --- a/docs/deprecated.zh.md +++ b/docs/deprecated.zh.md @@ -4,6 +4,13 @@ icon: material/delete-alert # 废弃功能列表 +#### 旧的 DNS 服务器格式 + +DNS 服务器已重构, +参阅 [迁移指南](/migration/#migrate-to-new-dns-servers). + +对旧格式的兼容性将在 sing-box 1.14.0 中被移除。 + ## 1.11.0 #### 旧的特殊出站 diff --git a/docs/migration.md b/docs/migration.md index 4943bb86..a2818e8f 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -2,6 +2,515 @@ icon: material/arrange-bring-forward --- +## 1.12.0 + +### Migrate to new DNS server formats + +DNS servers are refactored. + +!!! info "References" + + [DNS Server](/configuration/dns/server/) / + [Legacy DNS Server](/configuration/dns/server/legacy/) + +=== "Local" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "local" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "local" + } + ] + } + } + ``` + +=== "TCP" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "tcp://1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "tcp", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "UDP" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "TLS" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "tls://1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "tls", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "HTTPS" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "https://1.1.1.1/dns-query" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "https", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "QUIC" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "quic://1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "quic", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "HTTP3" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "h3://1.1.1.1/dns-query" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "h3", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "DHCP" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "dhcp://auto" + }, + { + "address": "dhcp://en0" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "dhcp", + }, + { + "type": "dhcp", + "interface": "en0" + } + ] + } + } + ``` + +=== "FakeIP" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1" + }, + { + "address": "fakeip", + "tag": "fakeip" + } + ], + "rules": [ + { + "query_type": [ + "A", + "AAAA" + ], + "server": "fakeip" + } + ], + "fakeip": { + "enable": true, + "inet4_range": "198.18.0.0/15", + "inet6_range": "fc00::/18" + } + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + }, + { + "type": "fakeip", + "tag": "fakeip", + "inet4_range": "198.18.0.0/15", + "inet6_range": "fc00::/18" + } + ], + "rules": [ + { + "query_type": [ + "A", + "AAAA" + ], + "server": "fakeip" + } + ] + } + } + ``` + +=== "RCode" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "rcode://refused" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "predefined", + "responses": [ + { + "rcode": "REFUSED" + } + ] + } + ] + } + } + ``` + +=== "Servers with domain address" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "https://dns.google/dns-query", + "address_resolver": "google" + }, + { + "tag": "google", + "address": "1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "https", + "server": "dns.google", + "domain_resolver": "google" + }, + { + "type": "udp", + "tag": "google", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "Servers with strategy" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1", + "strategy": "ipv4_only" + }, + { + "tag": "google", + "address": "8.8.8.8", + "strategy": "prefer_ipv6" + } + ], + "rules": [ + { + "domain": "google.com", + "server": "google" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + }, + { + "type": "udp", + "tag": "google", + "server": "8.8.8.8" + } + ], + "rules": [ + { + "domain": "google.com", + "server": "google", + "strategy": "prefer_ipv6" + } + ], + "strategy": "ipv4_only" + } + } + ``` + +=== "Servers with client subnet" + + === ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1" + }, + { + "tag": "google", + "address": "8.8.8.8", + "client_subnet": "1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + }, + { + "type": "udp", + "tag": "google", + "server": "8.8.8.8" + } + ], + "rules": [ + { + "domain": "google.com", + "server": "google", + "client_subnet": "1.1.1.1" + } + ] + } + } + ``` + ## 1.11.0 ### Migrate legacy special outbounds to rule actions diff --git a/docs/migration.zh.md b/docs/migration.zh.md index 32be5604..3cc45c2f 100644 --- a/docs/migration.zh.md +++ b/docs/migration.zh.md @@ -2,6 +2,515 @@ icon: material/arrange-bring-forward --- +## 1.12.0 + +### 迁移到新的 DNS 服务器格式 + +DNS 服务器已经重构。 + +!!! info "饮用" + + [DNS 服务器](/configuration/dns/server/) / + [旧 DNS 服务器](/configuration/dns/server/legacy/) + +=== "Local" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "local" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "local" + } + ] + } + } + ``` + +=== "TCP" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "tcp://1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "tcp", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "UDP" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "TLS" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "tls://1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "tls", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "HTTPS" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "https://1.1.1.1/dns-query" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "https", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "QUIC" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "quic://1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "quic", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "HTTP3" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "h3://1.1.1.1/dns-query" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "h3", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "DHCP" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "dhcp://auto" + }, + { + "address": "dhcp://en0" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "dhcp", + }, + { + "type": "dhcp", + "interface": "en0" + } + ] + } + } + ``` + +=== "FakeIP" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1" + }, + { + "address": "fakeip", + "tag": "fakeip" + } + ], + "rules": [ + { + "query_type": [ + "A", + "AAAA" + ], + "server": "fakeip" + } + ], + "fakeip": { + "enable": true, + "inet4_range": "198.18.0.0/15", + "inet6_range": "fc00::/18" + } + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + }, + { + "type": "fakeip", + "tag": "fakeip", + "inet4_range": "198.18.0.0/15", + "inet6_range": "fc00::/18" + } + ], + "rules": [ + { + "query_type": [ + "A", + "AAAA" + ], + "server": "fakeip" + } + ] + } + } + ``` + +=== "RCode" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "rcode://refused" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "predefined", + "responses": [ + { + "rcode": "REFUSED" + } + ] + } + ] + } + } + ``` + +=== "带有域名地址的服务器" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "https://dns.google/dns-query", + "address_resolver": "google" + }, + { + "tag": "google", + "address": "1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "https", + "server": "dns.google", + "domain_resolver": "google" + }, + { + "type": "udp", + "tag": "google", + "server": "1.1.1.1" + } + ] + } + } + ``` + +=== "带有域策略的服务器" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1", + "strategy": "ipv4_only" + }, + { + "tag": "google", + "address": "8.8.8.8", + "strategy": "prefer_ipv6" + } + ], + "rules": [ + { + "domain": "google.com", + "server": "google" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + }, + { + "type": "udp", + "tag": "google", + "server": "8.8.8.8" + } + ], + "rules": [ + { + "domain": "google.com", + "server": "google", + "strategy": "prefer_ipv6" + } + ], + "strategy": "ipv4_only" + } + } + ``` + +=== "带有客户端子网的服务器" + + === ":material-card-remove: 弃用的" + + ```json + { + "dns": { + "servers": [ + { + "address": "1.1.1.1" + }, + { + "tag": "google", + "address": "8.8.8.8", + "client_subnet": "1.1.1.1" + } + ] + } + } + ``` + + === ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "udp", + "server": "1.1.1.1" + }, + { + "type": "udp", + "tag": "google", + "server": "8.8.8.8" + } + ], + "rules": [ + { + "domain": "google.com", + "server": "google", + "client_subnet": "1.1.1.1" + } + ] + } + } + ``` + ## 1.11.0 ### 迁移旧的特殊出站到规则动作 @@ -129,7 +638,7 @@ icon: material/arrange-bring-forward } ``` -=== ":material-card-multiple: New" +=== ":material-card-multiple: 新的" ```json { diff --git a/mkdocs.yml b/mkdocs.yml index 4854fa4a..acab5853 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -80,7 +80,19 @@ nav: - configuration/log/index.md - DNS: - configuration/dns/index.md - - DNS Server: configuration/dns/server.md + - DNS Server: + - configuration/dns/server/index.md + - Legacy: configuration/dns/server/legacy.md + - Local: configuration/dns/server/local.md + - TCP: configuration/dns/server/tcp.md + - UDP: configuration/dns/server/udp.md + - TLS: configuration/dns/server/tls.md + - QUIC: configuration/dns/server/quic.md + - HTTPS: configuration/dns/server/https.md + - HTTP3: configuration/dns/server/http3.md + - Predefined: configuration/dns/server/predefined.md + - DHCP: configuration/dns/server/dhcp.md + - FakeIP: configuration/dns/server/fakeip.md - DNS Rule: configuration/dns/rule.md - DNS Rule Action: configuration/dns/rule_action.md - FakeIP: configuration/dns/fakeip.md From 8e2ed8d0f3b67fbc0b3577f915d89096b2fcf72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 29 Jan 2025 13:13:33 +0800 Subject: [PATCH 42/62] documentation: Outbound domain resolver --- docs/configuration/dns/rule.md | 10 +++- docs/configuration/dns/rule.zh.md | 10 +++- docs/configuration/route/geoip.md | 6 +- docs/configuration/route/geoip.zh.md | 6 +- docs/configuration/route/geosite.md | 6 +- docs/configuration/route/geosite.zh.md | 6 +- docs/configuration/route/index.md | 26 +++++++-- docs/configuration/route/index.zh.md | 16 +++++- docs/configuration/shared/dial.md | 48 +++++++++++++--- docs/configuration/shared/dial.zh.md | 44 ++++++++++++--- docs/deprecated.md | 6 ++ docs/deprecated.zh.md | 8 ++- docs/migration.md | 77 +++++++++++++++++++++++++- docs/migration.zh.md | 67 ++++++++++++++++++++++ 14 files changed, 297 insertions(+), 39 deletions(-) diff --git a/docs/configuration/dns/rule.md b/docs/configuration/dns/rule.md index 1f04b299..3039bffc 100644 --- a/docs/configuration/dns/rule.md +++ b/docs/configuration/dns/rule.md @@ -1,7 +1,11 @@ --- -icon: material/new-box +icon: material/alert-decagram --- +!!! quote "Changes in sing-box 1.12.0" + + :material-delete-clock: [outbound](#outbound) + !!! quote "Changes in sing-box 1.11.0" :material-plus: [action](#action) @@ -395,6 +399,10 @@ Invert match result. #### outbound +!!! failure "Deprecated in sing-box 1.12.0" + + `outbound` rule items are deprecated and will be removed in sing-box 1.14.0, check [Migration](/migration/#migrate-outbound-dns-rule-items-to-domain-resolver). + Match outbound. `any` can be used as a value to match any outbound. diff --git a/docs/configuration/dns/rule.zh.md b/docs/configuration/dns/rule.zh.md index bf0a03e2..94ca4535 100644 --- a/docs/configuration/dns/rule.zh.md +++ b/docs/configuration/dns/rule.zh.md @@ -1,7 +1,11 @@ --- -icon: material/new-box +icon: material/alert-decagram --- +!!! quote "sing-box 1.12.0 中的更改" + + :material-delete-clock: [outbound](#outbound) + !!! quote "sing-box 1.11.0 中的更改" :material-plus: [action](#action) @@ -395,6 +399,10 @@ Available values: `wifi`, `cellular`, `ethernet` and `other`. #### outbound +!!! failure "已在 sing-box 1.12.0 废弃" + + `outbound` 规则项已废弃且将在 sing-box 1.14.0 中被移除,参阅 [迁移指南](/migration/#migrate-outbound-dns-rule-items-to-domain-resolver)。 + 匹配出站。 `any` 可作为值用于匹配任意出站。 diff --git a/docs/configuration/route/geoip.md b/docs/configuration/route/geoip.md index a045574a..62162cdf 100644 --- a/docs/configuration/route/geoip.md +++ b/docs/configuration/route/geoip.md @@ -1,10 +1,10 @@ --- -icon: material/delete-clock +icon: material/note-remove --- -!!! failure "Deprecated in sing-box 1.8.0" +!!! failure "Removed in sing-box 1.12.0" - GeoIP is deprecated and will be removed in sing-box 1.12.0, check [Migration](/migration/#migrate-geoip-to-rule-sets). + GeoIP is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0, check [Migration](/migration/#migrate-geoip-to-rule-sets). ### Structure diff --git a/docs/configuration/route/geoip.zh.md b/docs/configuration/route/geoip.zh.md index eb7bbe2d..3d63a3b7 100644 --- a/docs/configuration/route/geoip.zh.md +++ b/docs/configuration/route/geoip.zh.md @@ -1,10 +1,10 @@ --- -icon: material/delete-clock +icon: material/note-remove --- -!!! failure "已在 sing-box 1.8.0 废弃" +!!! failure "已在 sing-box 1.12.0 中被移除" - GeoIP 已废弃且将在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geoip)。 + GeoIP 已在 sing-box 1.8.0 废弃且在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geoip)。 ### 结构 diff --git a/docs/configuration/route/geosite.md b/docs/configuration/route/geosite.md index 9a1b9dce..830d1158 100644 --- a/docs/configuration/route/geosite.md +++ b/docs/configuration/route/geosite.md @@ -1,10 +1,10 @@ --- -icon: material/delete-clock +icon: material/note-remove --- -!!! failure "Deprecated in sing-box 1.8.0" +!!! failure "Removed in sing-box 1.12.0" - Geosite is deprecated and will be removed in sing-box 1.12.0, check [Migration](/migration/#migrate-geosite-to-rule-sets). + Geosite is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0, check [Migration](/migration/#migrate-geosite-to-rule-sets). ### Structure diff --git a/docs/configuration/route/geosite.zh.md b/docs/configuration/route/geosite.zh.md index 7cec5b20..9afea3d7 100644 --- a/docs/configuration/route/geosite.zh.md +++ b/docs/configuration/route/geosite.zh.md @@ -1,10 +1,10 @@ --- -icon: material/delete-clock +icon: material/note-remove --- -!!! failure "已在 sing-box 1.8.0 废弃" +!!! failure "已在 sing-box 1.12.0 中被移除" - Geosite 已废弃且将在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geosite)。 + Geosite 已在 sing-box 1.8.0 废弃且在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geosite)。 ### 结构 diff --git a/docs/configuration/route/index.md b/docs/configuration/route/index.md index 1a1919e9..1fc9bfd2 100644 --- a/docs/configuration/route/index.md +++ b/docs/configuration/route/index.md @@ -1,9 +1,15 @@ --- -icon: material/new-box +icon: material/alert-decagram --- # Route +!!! quote "Changes in sing-box 1.12.0" + + :material-plus: [default_domain_resolver](#default_domain_resolver) + :material-note-remove: [geoip](#geoip) + :material-note-remove: [geosite](#geosite) + !!! quote "Changes in sing-box 1.11.0" :material-plus: [default_network_strategy](#default_network_strategy) @@ -22,8 +28,6 @@ icon: material/new-box ```json { "route": { - "geoip": {}, - "geosite": {}, "rules": [], "rule_set": [], "final": "", @@ -31,10 +35,16 @@ icon: material/new-box "override_android_vpn": false, "default_interface": "", "default_mark": 0, + "default_domain_resolver": "", // or {} "default_network_strategy": "", "default_network_type": [], "default_fallback_network_type": [], - "default_fallback_delay": "" + "default_fallback_delay": "", + + // Removed + + "geoip": {}, + "geosite": {} } } ``` @@ -97,6 +107,14 @@ Set routing mark by default. Takes no effect if `outbound.routing_mark` is set. +#### default_domain_resolver + +!!! question "Since sing-box 1.12.0" + +See [Dial Fields](/configuration/shared/dial/#domain_resolver) for details. + +Can be overrides by `outbound.domain_resolver`. + #### default_network_strategy !!! question "Since sing-box 1.11.0" diff --git a/docs/configuration/route/index.zh.md b/docs/configuration/route/index.zh.md index a224ddc4..3748a522 100644 --- a/docs/configuration/route/index.zh.md +++ b/docs/configuration/route/index.zh.md @@ -1,9 +1,15 @@ --- -icon: material/new-box +icon: material/alert-decagram --- # 路由 +!!! quote "sing-box 1.12.0 中的更改" + + :material-plus: [default_domain_resolver](#default_domain_resolver) + :material-note-remove: [geoip](#geoip) + :material-note-remove: [geosite](#geosite) + !!! quote "sing-box 1.11.0 中的更改" :material-plus: [network_strategy](#network_strategy) @@ -100,6 +106,14 @@ icon: material/new-box 如果设置了 `outbound.routing_mark` 设置,则不生效。 +#### default_domain_resolver + +!!! question "自 sing-box 1.12.0 起" + +详情参阅 [拨号字段](/configuration/shared/dial/#domain_resolver)。 + +可以被 `outbound.domain_resolver` 覆盖。 + #### network_strategy !!! question "自 sing-box 1.11.0 起" diff --git a/docs/configuration/shared/dial.md b/docs/configuration/shared/dial.md index 5f654ae2..e852d57b 100644 --- a/docs/configuration/shared/dial.md +++ b/docs/configuration/shared/dial.md @@ -2,6 +2,11 @@ icon: material/new-box --- +!!! quote "Changes in sing-box 1.12.0" + + :material-plus: [domain_resolver](#domain_resolver) + :material-delete-clock: [domain_strategy](#domain_strategy) + !!! quote "Changes in sing-box 1.11.0" :material-plus: [network_strategy](#network_strategy) @@ -23,11 +28,14 @@ icon: material/new-box "tcp_fast_open": false, "tcp_multi_path": false, "udp_fragment": false, - "domain_strategy": "prefer_ipv6", + "domain_resolver": "", // or {} "network_strategy": "default", "network_type": [], "fallback_network_type": [], - "fallback_delay": "300ms" + "fallback_delay": "300ms", + + // Deprecated + "domain_strategy": "prefer_ipv6" } ``` @@ -92,16 +100,22 @@ decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". -#### domain_strategy +#### domain_resolver -Available values: `prefer_ipv4`, `prefer_ipv6`, `ipv4_only`, `ipv6_only`. +!!! warning "" -If set, the requested domain name will be resolved to IP before connect. + `outbound` DNS rule items are deprecated and will be removed in sing-box 1.14.0, so this item will be required for outbound/endpoints using domain name in server address since sing-box 1.14.0. -| Outbound | Effected domains | Fallback Value | -|----------|--------------------------|-------------------------------------------| -| `direct` | Domain in request | Take `inbound.domain_strategy` if not set | -| others | Domain in server address | / | +Set domain resolver to use for resolving domain names. + +This option uses the same format as the [route DNS rule action](/configuration/dns/rule_action/#route) without the `action` field. + +Setting this option directly to a string is equivalent to setting `server` of this options. + +| Outbound/Endpoints | Effected domains | +|--------------------|--------------------------| +| `direct` | Domain in request | +| others | Domain in server address | #### network_strategy @@ -171,3 +185,19 @@ back to other interfaces. Only take effect when `domain_strategy` or `network_strategy` is set. `300ms` is used by default. + +#### domain_strategy + +!!! failure "Deprecated in sing-box 1.12.0" + + `domain_strategy` is merged to [domain_resolver](#domain_resolver) in sing-box 1.12.0. + +Available values: `prefer_ipv4`, `prefer_ipv6`, `ipv4_only`, `ipv6_only`. + +If set, the requested domain name will be resolved to IP before connect. + +| Outbound | Effected domains | Fallback Value | +|----------|--------------------------|-------------------------------------------| +| `direct` | Domain in request | Take `inbound.domain_strategy` if not set | +| others | Domain in server address | / | + diff --git a/docs/configuration/shared/dial.zh.md b/docs/configuration/shared/dial.zh.md index ab83c44c..66e1436e 100644 --- a/docs/configuration/shared/dial.zh.md +++ b/docs/configuration/shared/dial.zh.md @@ -2,6 +2,11 @@ icon: material/new-box --- +!!! quote "sing-box 1.12.0 中的更改" + + :material-plus: [domain_resolver](#domain_resolver) + :material-delete-clock: [domain_strategy](#domain_strategy) + !!! quote "sing-box 1.11.0 中的更改" :material-plus: [network_strategy](#network_strategy) @@ -23,11 +28,15 @@ icon: material/new-box "tcp_fast_open": false, "tcp_multi_path": false, "udp_fragment": false, - "domain_strategy": "prefer_ipv6", + "domain_resolver": "", // 或 {} "network_strategy": "", "network_type": [], "fallback_network_type": [], - "fallback_delay": "300ms" + "fallback_delay": "300ms", + + // 废弃的 + + "domain_strategy": "prefer_ipv6" } ``` @@ -90,16 +99,22 @@ icon: material/new-box 持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。 有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。 -#### domain_strategy +#### domain_resolver -可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。 +!!! warning "" -如果设置,域名将在请求发出之前解析为 IP。 + `outbound` DNS 规则项已弃用,且将在 sing-box 1.14.0 中被移除。因此,从 sing-box 1.14.0 版本开始,所有在服务器地址中使用域名的出站/端点均需配置此项。 -| 出站 | 受影响的域名 | 默认回退值 | -|----------|-----------|---------------------------| -| `direct` | 请求中的域名 | `inbound.domain_strategy` | -| others | 服务器地址中的域名 | / | +用于设置解析域名的域名解析器。 + +此选项的格式与 [路由 DNS 规则动作](/configuration/dns/rule_action/#route) 相同,但不包含 `action` 字段。 + +若直接将此选项设置为字符串,则等同于设置该选项的 `server` 字段。 + +| 出站/端点 | 受影响的域名 | +|----------------|---------------------------| +| `direct` | 请求中的域名 | +| 其他类型 | 服务器地址中的域名 | #### network_strategy @@ -160,3 +175,14 @@ icon: material/new-box 仅当 `domain_strategy` 或 `network_strategy` 已设置时生效。 默认使用 `300ms`。 + +#### domain_strategy + +可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。 + +如果设置,域名将在请求发出之前解析为 IP。 + +| 出站 | 受影响的域名 | 默认回退值 | +|----------|-----------|---------------------------| +| `direct` | 请求中的域名 | `inbound.domain_strategy` | +| others | 服务器地址中的域名 | / | \ No newline at end of file diff --git a/docs/deprecated.md b/docs/deprecated.md index 40bbc3a4..128c0709 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -13,6 +13,12 @@ check [Migration](../migration/#migrate-to-new-dns-servers). Compatibility for old formats will be removed in sing-box 1.14.0. +#### `outbound` DNS rule item + +Legacy `outbound` DNS rules are deprecated +and can be replaced by dial fields, +check [Migration](../migration/#migrate-outbound-dns-rule-items-to-domain-resolver). + ## 1.11.0 #### Legacy special outbounds diff --git a/docs/deprecated.zh.md b/docs/deprecated.zh.md index 29f38742..2c0f5578 100644 --- a/docs/deprecated.zh.md +++ b/docs/deprecated.zh.md @@ -11,6 +11,12 @@ DNS 服务器已重构, 对旧格式的兼容性将在 sing-box 1.14.0 中被移除。 +#### `outbound` DNS 规则项 + +旧的 `outbound` DNS 规则已废弃, +且可被拨号字段代替, +参阅 [迁移指南](/migration/#migrate-outbound-dns-rule-items-to-domain-resolver). + ## 1.11.0 #### 旧的特殊出站 @@ -27,7 +33,7 @@ DNS 服务器已重构, 旧字段将在 sing-box 1.13.0 中被移除。 -#### direct 出站中的目标地址覆盖字段 +#### direct 出站中的目标地址覆盖字段 direct 出站中的目标地址覆盖字段(`override_address` / `override_port`)已废弃且可以通过规则动作替代, 参阅 [迁移指南](/migration/#migrate-destination-override-fields-to-route-options)。 diff --git a/docs/migration.md b/docs/migration.md index a2818e8f..62e09e71 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -6,7 +6,7 @@ icon: material/arrange-bring-forward ### Migrate to new DNS server formats -DNS servers are refactored. +DNS servers are refactored for better performance and scalability. !!! info "References" @@ -511,6 +511,81 @@ DNS servers are refactored. } ``` +### Migrate outbound DNS rule items to domain resolver + +The legacy outbound DNS rules are deprecated and can be replaced by new domain resolver options. + +!!! info "References" + + [DNS rule](/configuration/dns/rule/#outbound) / + [Dial Fields](/configuration/shared/dial/#domain_resolver) / + [Route](/configuration/route/#domain_resolver) + +=== ":material-card-remove: Deprecated" + + ```json + { + "dns": { + "servers": [ + { + "address": "local", + "tag": "local" + } + ], + "rules": [ + { + "outbound": "any", + "server": "local" + } + ] + }, + "outbounds": [ + { + "type": "socks", + "server": "example.org", + "server_port": 2080 + } + ] + } + ``` + +=== ":material-card-multiple: New" + + ```json + { + "dns": { + "servers": [ + { + "type": "local" + } + ] + }, + "outbounds": [ + { + "type": "socks", + "server": "example.org", + "server_port": 2080, + "domain_resolver": { + "server": "local", + "rewrite_tll": 60, + "client_subnet": "1.1.1.1" + }, + // or "domain_resolver": "local", + } + ], + + // or + + "route": { + "default_domain_resolver": { + "server": "local", + "rewrite_tll": 60, + "client_subnet": "1.1.1.1" + } + } + } + ``` + ## 1.11.0 ### Migrate legacy special outbounds to rule actions diff --git a/docs/migration.zh.md b/docs/migration.zh.md index 3cc45c2f..12044669 100644 --- a/docs/migration.zh.md +++ b/docs/migration.zh.md @@ -511,6 +511,73 @@ DNS 服务器已经重构。 } ``` +### 迁移 outbound DNS 规则项到域解析选项 + +旧的 `outbound` DNS 规则已废弃,且可新的域解析选项代替。 + +!!! info "参考" + + [DNS 规则](/configuration/dns/rule/#outbound) / + [拨号字段](/configuration/shared/dial/#domain_resolver) / + [路由](/configuration/route/#default_domain_resolver) + +=== ":material-card-remove: 废弃的" + + ```json + { + "dns": { + "servers": [ + { + "address": "local", + "tag": "local" + } + ], + "rules": [ + { + "outbound": "any", + "server": "local" + } + ] + }, + "outbounds": [ + { + "type": "socks", + "server": "example.org", + "server_port": 2080 + } + ] + } + ``` + +=== ":material-card-multiple: 新的" + + ```json + { + "dns": { + "servers": [ + { + "type": "local" + } + ] + }, + "outbounds": [ + { + "type": "socks", + "server": "example.org", + "server_port": 2080, + "domain_resolver": "local", + } + ], + "route": { + "default_domain_resolver": { + "server": "local", + "rewrite_tll": 60, + "client_subnet": "1.1.1.1" + } + } + } + ``` + ## 1.11.0 ### 迁移旧的特殊出站到规则动作 From 4cf68c4aa90fd148c96c862704d566b3425dfd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 30 Jan 2025 13:29:16 +0800 Subject: [PATCH 43/62] documentation: TLS fragment --- docs/configuration/route/rule_action.md | 31 +++++++++++++++++++++- docs/configuration/route/rule_action.zh.md | 27 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/configuration/route/rule_action.md b/docs/configuration/route/rule_action.md index 31256e25..567b9eb6 100644 --- a/docs/configuration/route/rule_action.md +++ b/docs/configuration/route/rule_action.md @@ -2,6 +2,11 @@ icon: material/new-box --- +!!! quote "Changes in sing-box 1.12.0" + + :material-plus: [tls_fragment](#tls_fragment) + :material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay) + ## Final actions ### route @@ -81,7 +86,9 @@ Not available when `method` is set to drop. "fallback_delay": "", "udp_disable_domain_unmapping": false, "udp_connect": false, - "udp_timeout": "" + "udp_timeout": "", + "tls_fragment": false, + "tls_fragment_fallback_delay": "" } ``` @@ -148,6 +155,28 @@ If no protocol is sniffed, the following ports will be recognized as protocols b | 443 | `quic` | | 3478 | `stun` | +#### tls_fragment + +!!! question "Since sing-box 1.12.0" + +Fragment TLS handshakes to bypass firewalls. + +This feature is intended to circumvent simple firewalls based on **plaintext packet matching**, and should not be used to circumvent real censorship. + +Since it is not designed for performance, it should not be applied to all connections, but only to server names that are known to be blocked. + +On Linux, Apple platforms, (administrator privileges required) Windows, the wait time can be automatically detected, otherwise it will fall back to waiting for a fixed time specified by `tls_fragment_fallback_delay`. + +In addition, if the actual wait time is less than 20ms, it will also fall back to waiting for a fixed time, because the target is considered to be local or behind a transparent proxy. + +#### tls_fragment_fallback_delay + +!!! question "Since sing-box 1.12.0" + +The fallback value used when TLS segmentation cannot automatically determine the wait time. + +`500ms` is used by default. + ### sniff ```json diff --git a/docs/configuration/route/rule_action.zh.md b/docs/configuration/route/rule_action.zh.md index 544918d4..a8eca8a2 100644 --- a/docs/configuration/route/rule_action.zh.md +++ b/docs/configuration/route/rule_action.zh.md @@ -2,6 +2,11 @@ icon: material/new-box --- +!!! quote "sing-box 1.12.0 中的更改" + + :material-plus: [tls_fragment](#tls_fragment) + :material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay) + ## 最终动作 ### route @@ -146,6 +151,28 @@ UDP 连接超时时间。 | 443 | `quic` | | 3478 | `stun` | +#### tls_fragment + +!!! question "自 sing-box 1.12.0 起" + +通过分段 TLS 握手数据包来绕过防火墙检测。 + +此功能旨在规避基于**明文数据包匹配**的简单防火墙,不应该用于规避真的审查。 + +由于它不是为性能设计的,不应被应用于所有连接,而仅应用于已知被阻止的服务器名称。 + +在 Linux、Apple 平台和需要管理员权限的 Windows 系统上,可自动检测等待时间。若无法自动检测,将回退使用 `tls_fragment_fallback_delay` 指定的固定等待时间。 + +此外,若实际等待时间小于 20 毫秒,同样会回退至固定等待时间模式,因为此时判定目标处于本地或透明代理之后。 + +#### tls_fragment_fallback_delay + +!!! question "自 sing-box 1.12.0 起" + +当 TLS 分片功能无法自动判定等待时间时使用的回退值。 + +默认使用 `500ms`。 + ### sniff ```json From 7b44e98fc81cf8124b57fd4b901197e5fb64b8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 30 Jan 2025 14:27:25 +0800 Subject: [PATCH 44/62] documentation: Certificate store --- docs/configuration/certificate/index.md | 54 +++++++++++++++++++++++++ mkdocs.yml | 4 +- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 docs/configuration/certificate/index.md diff --git a/docs/configuration/certificate/index.md b/docs/configuration/certificate/index.md new file mode 100644 index 00000000..698fec70 --- /dev/null +++ b/docs/configuration/certificate/index.md @@ -0,0 +1,54 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# Certificate + +### Structure + +```json +{ + "store": "", + "certificate": [], + "certificate_path": [], + "certificate_directory_path": [] +} +``` + +!!! note "" + + You can ignore the JSON Array [] tag when the content is only one item + +### Fields + +#### store + +The default X509 trusted CA certificate list. + +| Type | Description | +|--------------------|---------------------------------------------------------------------------------------------------------------| +| `system` (default) | System trusted CA certificates | +| `mozilla` | [Mozilla Included List](https://wiki.mozilla.org/CA/Included_Certificates) with China CA certificates removed | +| `none` | Empty list | + +#### certificate + +The certificate line array to trust, in PEM format. + +#### certificate_path + +!!! note "" + + Will be automatically reloaded if file modified. + +The paths to certificates to trust, in PEM format. + +#### certificate_directory_path + +!!! note "" + + Will be automatically reloaded if file modified. + +The directory path to search for certificates to trust,in PEM format. diff --git a/mkdocs.yml b/mkdocs.yml index acab5853..5758525a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -96,8 +96,8 @@ nav: - DNS Rule: configuration/dns/rule.md - DNS Rule Action: configuration/dns/rule_action.md - FakeIP: configuration/dns/fakeip.md - - NTP: - - configuration/ntp/index.md + - NTP: configuration/ntp/index.md + - Certificate: configuration/certificate/index.md - Route: - configuration/route/index.md - GeoIP: configuration/route/geoip.md From 92e20421f0e7acec4746478f12526d90505a9ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 30 Jan 2025 14:30:37 +0800 Subject: [PATCH 45/62] documentation: Remove outdated icons --- docs/configuration/experimental/clash-api.md | 4 ---- docs/configuration/experimental/clash-api.zh.md | 4 ---- docs/configuration/route/sniff.md | 4 ---- docs/configuration/route/sniff.zh.md | 4 ---- docs/configuration/rule-set/adguard.md | 4 ---- docs/configuration/rule-set/adguard.zh.md | 4 ---- docs/configuration/rule-set/index.md | 4 ---- docs/configuration/rule-set/index.zh.md | 4 ---- docs/configuration/shared/tls.md | 4 ---- docs/configuration/shared/tls.zh.md | 4 ---- 10 files changed, 40 deletions(-) diff --git a/docs/configuration/experimental/clash-api.md b/docs/configuration/experimental/clash-api.md index 7425143e..a02e87a9 100644 --- a/docs/configuration/experimental/clash-api.md +++ b/docs/configuration/experimental/clash-api.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! quote "Changes in sing-box 1.10.0" :material-plus: [access_control_allow_origin](#access_control_allow_origin) diff --git a/docs/configuration/experimental/clash-api.zh.md b/docs/configuration/experimental/clash-api.zh.md index b3d8aeaf..c6146fb8 100644 --- a/docs/configuration/experimental/clash-api.zh.md +++ b/docs/configuration/experimental/clash-api.zh.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! quote "sing-box 1.10.0 中的更改" :material-plus: [access_control_allow_origin](#access_control_allow_origin) diff --git a/docs/configuration/route/sniff.md b/docs/configuration/route/sniff.md index 40de038c..5c8f218b 100644 --- a/docs/configuration/route/sniff.md +++ b/docs/configuration/route/sniff.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! quote "Changes in sing-box 1.10.0" :material-plus: QUIC client type detect support for QUIC diff --git a/docs/configuration/route/sniff.zh.md b/docs/configuration/route/sniff.zh.md index 4efa4538..cd582517 100644 --- a/docs/configuration/route/sniff.zh.md +++ b/docs/configuration/route/sniff.zh.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! quote "sing-box 1.10.0 中的更改" :material-plus: QUIC 的 客户端类型探测支持 diff --git a/docs/configuration/rule-set/adguard.md b/docs/configuration/rule-set/adguard.md index bda73794..c8bd32fa 100644 --- a/docs/configuration/rule-set/adguard.md +++ b/docs/configuration/rule-set/adguard.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! question "Since sing-box 1.10.0" sing-box supports some rule-set formats from other projects which cannot be fully translated to sing-box, diff --git a/docs/configuration/rule-set/adguard.zh.md b/docs/configuration/rule-set/adguard.zh.md index 026f2e0b..82773280 100644 --- a/docs/configuration/rule-set/adguard.zh.md +++ b/docs/configuration/rule-set/adguard.zh.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! question "自 sing-box 1.10.0 起" sing-box 支持其他项目的一些规则集格式,这些格式无法完全转换为 sing-box, diff --git a/docs/configuration/rule-set/index.md b/docs/configuration/rule-set/index.md index c905e110..944ea838 100644 --- a/docs/configuration/rule-set/index.md +++ b/docs/configuration/rule-set/index.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! quote "Changes in sing-box 1.10.0" :material-plus: `type: inline` diff --git a/docs/configuration/rule-set/index.zh.md b/docs/configuration/rule-set/index.zh.md index c3b86b6d..c38a57b5 100644 --- a/docs/configuration/rule-set/index.zh.md +++ b/docs/configuration/rule-set/index.zh.md @@ -1,7 +1,3 @@ ---- -icon: material/new-box ---- - !!! quote "sing-box 1.10.0 中的更改" :material-plus: `type: inline` diff --git a/docs/configuration/shared/tls.md b/docs/configuration/shared/tls.md index 7a6c9d5e..f2a716a7 100644 --- a/docs/configuration/shared/tls.md +++ b/docs/configuration/shared/tls.md @@ -1,7 +1,3 @@ ---- -icon: material/alert-decagram ---- - !!! quote "Changes in sing-box 1.10.0" :material-alert-decagram: [utls](#utls) diff --git a/docs/configuration/shared/tls.zh.md b/docs/configuration/shared/tls.zh.md index b254e083..6cfc5f36 100644 --- a/docs/configuration/shared/tls.zh.md +++ b/docs/configuration/shared/tls.zh.md @@ -1,7 +1,3 @@ ---- -icon: material/alert-decagram ---- - !!! quote "sing-box 1.10.0 中的更改" :material-alert-decagram: [utls](#utls) From a034f82f6ae78b13e2d8c3217a71edfb38665b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 12 Feb 2025 08:31:21 +0800 Subject: [PATCH 46/62] Build legacy binaries with latest Go --- .github/setup_legacy_go.sh | 22 ++++++++++++++++++++++ .github/workflows/build.yml | 10 +++------- .goreleaser.yaml | 9 ++++----- 3 files changed, 29 insertions(+), 12 deletions(-) create mode 100755 .github/setup_legacy_go.sh diff --git a/.github/setup_legacy_go.sh b/.github/setup_legacy_go.sh new file mode 100755 index 00000000..200f6d41 --- /dev/null +++ b/.github/setup_legacy_go.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +VERSION="1.23.6" +wget "https://dl.google.com/go/go${VERSION}.linux-amd64.tar.gz" +tar -xzf "go${VERSION}.linux-amd64.tar.gz" +mv go $HOME/go/go_legacy +cd $HOME/go/go_legacy + +# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 +# this patch file only works on golang1.23.x +# that means after golang1.24 release it must be changed +# see: https://github.com/MetaCubeX/go/commits/release-branch.go1.23/ +# revert: +# 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" +# 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" +# 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" +# a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries" + +curl https://github.com/MetaCubeX/go/commit/9ac42137ef6730e8b7daca016ece831297a1d75b.diff | patch --verbose -p 1 +curl https://github.com/MetaCubeX/go/commit/21290de8a4c91408de7c2b5b68757b1e90af49dd.diff | patch --verbose -p 1 +curl https://github.com/MetaCubeX/go/commit/6a31d3fa8e47ddabc10bd97bff10d9a85f4cfb76.diff | patch --verbose -p 1 +curl https://github.com/MetaCubeX/go/commit/69e2eed6dd0f6d815ebf15797761c13f31213dd6.diff | patch --verbose -p 1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 98316ddd..77297ade 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,7 +112,6 @@ jobs: - name: darwin_amd64 goos: darwin goarch: amd64 - require_legacy_go: true - name: android_arm64 goos: android goarch: arm64 @@ -141,14 +140,11 @@ jobs: uses: actions/cache@v4 with: path: | - ~/go/go1.20.14 - key: go120 + ~/go/go_legacy + key: go_legacy_1236 - name: Setup legacy Go if: matrix.require_legacy_go && steps.cache-legacy-go.outputs.cache-hit != 'true' - run: |- - wget https://dl.google.com/go/go1.20.14.linux-amd64.tar.gz - tar -xzf go1.20.14.linux-amd64.tar.gz - mv go $HOME/go/go1.20.14 + run: bash .github/setup_legacy_go.sh - name: Setup Android NDK if: matrix.goos == 'android' uses: nttld/setup-ndk@v1 diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 9eb02c94..2315826f 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -51,12 +51,11 @@ builds: - with_clash_api env: - CGO_ENABLED=0 - - GOROOT={{ .Env.GOPATH }}/go1.20.14 - tool: "{{ .Env.GOPATH }}/go1.20.14/bin/go" + - GOROOT={{ .Env.GOPATH }}/go_legacy + tool: "{{ .Env.GOPATH }}/go_legacy/bin/go" targets: - windows_amd64_v1 - windows_386 - - darwin_amd64_v1 - id: android <<: *template env: @@ -122,8 +121,8 @@ nfpms: - deb - rpm - archlinux -# - apk -# - ipk + # - apk + # - ipk priority: extra contents: - src: release/config/config.json From 6ceaee4188a6a6badb4ca8fd2408d96ff81700c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 12 Feb 2025 20:09:21 +0800 Subject: [PATCH 47/62] Add Tailscale endpoint --- .goreleaser.fury.yaml | 1 + .goreleaser.yaml | 2 + Makefile | 3 +- cmd/internal/build_libbox/main.go | 2 +- common/dialer/dialer.go | 3 + constant/dns.go | 1 + constant/proxy.go | 1 + dns/router.go | 3 - docs/configuration/dns/server/tailscale.md | 83 ++++ docs/configuration/endpoint/tailscale.md | 99 +++++ docs/installation/build-from-source.md | 1 + docs/installation/build-from-source.zh.md | 1 + go.mod | 70 ++- go.sum | 161 +++++-- include/registry.go | 2 + include/tailscale.go | 17 + include/tailscale_stub.go | 27 ++ mkdocs.yml | 2 + option/tailscale.go | 24 ++ protocol/tailscale/dns_transport.go | 320 ++++++++++++++ protocol/tailscale/endpoint.go | 473 +++++++++++++++++++++ protocol/tailscale/protect_android.go | 16 + protocol/tailscale/protect_nonandroid.go | 8 + 23 files changed, 1269 insertions(+), 51 deletions(-) create mode 100644 docs/configuration/dns/server/tailscale.md create mode 100644 docs/configuration/endpoint/tailscale.md create mode 100644 include/tailscale.go create mode 100644 include/tailscale_stub.go create mode 100644 option/tailscale.go create mode 100644 protocol/tailscale/dns_transport.go create mode 100644 protocol/tailscale/endpoint.go create mode 100644 protocol/tailscale/protect_android.go create mode 100644 protocol/tailscale/protect_nonandroid.go diff --git a/.goreleaser.fury.yaml b/.goreleaser.fury.yaml index d80dd408..de5c5db9 100644 --- a/.goreleaser.fury.yaml +++ b/.goreleaser.fury.yaml @@ -19,6 +19,7 @@ builds: - with_reality_server - with_acme - with_clash_api + - with_tailscale env: - CGO_ENABLED=0 targets: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 2315826f..4d7fd502 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -21,6 +21,7 @@ builds: - with_reality_server - with_acme - with_clash_api + - with_tailscale env: - CGO_ENABLED=0 targets: @@ -49,6 +50,7 @@ builds: - with_reality_server - with_acme - with_clash_api + - with_tailscale env: - CGO_ENABLED=0 - GOROOT={{ .Env.GOPATH }}/go_legacy diff --git a/Makefile b/Makefile index 663ae922..ab399a29 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,8 @@ NAME = sing-box COMMIT = $(shell git rev-parse --short HEAD) TAGS_GO120 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api,with_quic,with_utls TAGS_GO121 = with_ech -TAGS ?= $(TAGS_GO118),$(TAGS_GO120),$(TAGS_GO121) +TAGS_GO123 = with_tailscale +TAGS ?= $(TAGS_GO118),$(TAGS_GO120),$(TAGS_GO121),$(TAGS_GO123) TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server GOHOSTOS = $(shell go env GOHOSTOS) diff --git a/cmd/internal/build_libbox/main.go b/cmd/internal/build_libbox/main.go index e37a9ff4..56cf8688 100644 --- a/cmd/internal/build_libbox/main.go +++ b/cmd/internal/build_libbox/main.go @@ -58,7 +58,7 @@ func init() { sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=") debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag) - sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_ech", "with_utls", "with_clash_api") + sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_ech", "with_utls", "with_clash_api", "with_tailscale") iosTags = append(iosTags, "with_dhcp", "with_low_memory", "with_conntrack") debugTags = append(debugTags, "debug") } diff --git a/common/dialer/dialer.go b/common/dialer/dialer.go index 812e5575..0efc7e9d 100644 --- a/common/dialer/dialer.go +++ b/common/dialer/dialer.go @@ -22,6 +22,7 @@ type Options struct { RemoteIsDomain bool DirectResolver bool ResolverOnDetour bool + NewDialer bool } // TODO: merge with NewWithOptions @@ -100,6 +101,8 @@ func NewWithOptions(options Options) (N.Dialer, error) { } dnsQueryOptions.Transport = transport resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay) + } else if options.NewDialer { + return nil, E.New("missing domain resolver for domain server address") } else { deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver) } diff --git a/constant/dns.go b/constant/dns.go index 99461a27..0a444ff0 100644 --- a/constant/dns.go +++ b/constant/dns.go @@ -27,6 +27,7 @@ const ( DNSTypePreDefined = "predefined" DNSTypeFakeIP = "fakeip" DNSTypeDHCP = "dhcp" + DNSTypeTailscale = "tailscale" ) const ( diff --git a/constant/proxy.go b/constant/proxy.go index 3197de60..45e79f84 100644 --- a/constant/proxy.go +++ b/constant/proxy.go @@ -23,6 +23,7 @@ const ( TypeVLESS = "vless" TypeTUIC = "tuic" TypeHysteria2 = "hysteria2" + TypeTailscale = "tailscale" ) const ( diff --git a/dns/router.go b/dns/router.go index 8ecb8891..4102128e 100644 --- a/dns/router.go +++ b/dns/router.go @@ -174,7 +174,6 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int, options.ClientSubnet = legacyTransport.LegacyClientSubnet() } } - r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) return transport, currentRule, currentRuleIndex case *R.RuleActionDNSRouteOptions: if action.Strategy != C.DomainStrategyAsIS { @@ -189,9 +188,7 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int, if action.ClientSubnet.IsValid() { options.ClientSubnet = action.ClientSubnet } - r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) case *R.RuleActionReject: - r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action()) return nil, currentRule, currentRuleIndex } } diff --git a/docs/configuration/dns/server/tailscale.md b/docs/configuration/dns/server/tailscale.md new file mode 100644 index 00000000..71744858 --- /dev/null +++ b/docs/configuration/dns/server/tailscale.md @@ -0,0 +1,83 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +# Tailscale + +### Structure + +```json +{ + "dns": { + "servers": [ + { + "type": "tailscale", + "tag": "", + + "endpoint": "ts-ep", + "accept_default_resolvers": false + } + ] + } +} +``` + +### Fields + +#### endpoint + +==Required== + +The tag of the Tailscale endpoint. + +#### accept_default_resolvers + +Indicates whether default DNS resolvers should be accepted for fallback queries in addition to MagicDNS。 + +if not enabled, NXDOMAIN will be returned for non-Tailscale domain queries. + +### Examples + +=== "MagicDNS only" + + ```json + { + "dns": { + "servers": [ + { + "type": "local", + "tag": "local" + }, + { + "type": "tailscale", + "tag": "ts", + "endpoint": "ts-ep" + } + ], + "rules": [ + { + "ip_accept_any": true, + "server": "ts" + } + ] + } + } + ``` + +=== "Use as global DNS" + + ```json + { + "dns": { + "servers": [ + { + "type": "tailscale", + "endpoint": "ts-ep", + "accept_default_resolvers": true + } + ] + } + } + ``` \ No newline at end of file diff --git a/docs/configuration/endpoint/tailscale.md b/docs/configuration/endpoint/tailscale.md new file mode 100644 index 00000000..298b68ce --- /dev/null +++ b/docs/configuration/endpoint/tailscale.md @@ -0,0 +1,99 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + +### Structure + +```json +{ + "type": "tailscale", + "tag": "ts-ep", + "state_directory": "", + "auth_key": "", + "control_url": "", + "ephemeral": false, + "hostname": "", + "exit_node": "", + "exit_node_allow_lan_access": false, + "advertise_routes": [], + "advertise_exit_node": false, + "udp_timeout": "5m", + + ... // Dial Fields +} +``` + +### Fields + +#### state_directory + +The directory where the Tailscale state is stored. + +`tailscale` is used by default. + +Example: `$HOME/.tailscale` + +#### auth_key + +!!! note + + Auth key is not required. By default, sing-box will log the login URL (or popup a notification on graphical clients). + +The auth key to create the node. If the node is already created (from state previously stored), then this field is not +used. + +#### control_url + +The coordination server URL. + +`https://controlplane.tailscale.com` is used by default. + +#### ephemeral + +Indicates whether the instance should register as an Ephemeral node (https://tailscale.com/s/ephemeral-nodes). + +#### hostname + +The hostname of the node. + +System hostname is used by default. + +Example: `localhost` + +#### exit_node + +The exit node name or IP address to use. + +#### exit_node_allow_lan_access + +!!! note + + When the exit node does not have a corresponding advertised route, private traffics cannot be routed to the exit node even if `exit_node_allow_lan_access is` set. + +Indicates whether locally accessible subnets should be routed directly or via the exit node. + +#### advertise_routes + +CIDR prefixes to advertise into the Tailscale network as reachable through the current node. + +Example: `["192.168.1.1/24"]` + +#### advertise_exit_node + +Indicates whether the node should advertise itself as an exit node. + +#### udp_timeout + +UDP NAT expiration time. + +`5m` will be used by default. + +### Dial Fields + +!!! note + + Dial Fields in Tailscale endpoints only control how it connects to the control plane and have nothing to do with actual connections. + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/installation/build-from-source.md b/docs/installation/build-from-source.md index e7c92ef4..8c4d4923 100644 --- a/docs/installation/build-from-source.md +++ b/docs/installation/build-from-source.md @@ -60,5 +60,6 @@ go build -tags "tag_a tag_b" ./cmd/sing-box | `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). | | `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). | | `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). | +| `with_tailscale` | :material-check: | Build with Tailscale support, see [Tailscale endpoint](/configuration/endpoint/tailscale) | It is not recommended to change the default build tag list unless you really know what you are adding. diff --git a/docs/installation/build-from-source.zh.md b/docs/installation/build-from-source.zh.md index f0bcc49b..7de7fcf4 100644 --- a/docs/installation/build-from-source.zh.md +++ b/docs/installation/build-from-source.zh.md @@ -60,5 +60,6 @@ go build -tags "tag_a tag_b" ./cmd/sing-box | `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). | | `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). | | `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). | +| `with_tailscale` | :material-check: | Build with Tailscale support, see [Tailscale endpoint](/configuration/endpoint/tailscale) | 除非您确实知道您正在启用什么,否则不建议更改默认构建标签列表。 diff --git a/go.mod b/go.mod index 28f84a54..c0bdbfcf 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/sagernet/sing-box -go 1.20 +go 1.23.1 + +toolchain go1.24.0 require ( github.com/caddyserver/certmagic v0.20.0 @@ -35,6 +37,7 @@ require ( github.com/sagernet/sing-tun v0.6.1 github.com/sagernet/sing-vmess v0.2.0 github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 + github.com/sagernet/tailscale v1.79.0-mod.1 github.com/sagernet/utls v1.6.7 github.com/sagernet/wireguard-go v0.0.1-beta.5 github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 @@ -56,48 +59,87 @@ require ( //replace github.com/sagernet/sing => ../sing require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/andybalholm/brotli v1.0.6 // indirect + github.com/akutz/memconn v0.1.0 // indirect + github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/coder/websocket v1.8.12 // indirect + github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect + github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.6.0 // indirect + github.com/gaissmai/bart v0.11.1 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect + github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect + github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/csrf v1.7.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect + github.com/hdevalence/ed25519consensus v0.2.0 // indirect + github.com/illarion/gonotify/v2 v2.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.17.4 // indirect + github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect + github.com/jsimonetti/rtnetlink v1.4.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/libdns/libdns v0.2.2 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect - github.com/mdlayher/socket v0.4.1 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/onsi/ginkgo/v2 v2.9.7 // indirect - github.com/pierrec/lz4/v4 v4.1.14 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/mdlayher/sdnotify v1.0.0 // indirect + github.com/mdlayher/socket v0.5.0 // indirect + github.com/mitchellh/go-ps v1.0.0 // indirect + github.com/onsi/ginkgo/v2 v2.17.2 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect + github.com/safchain/ethtool v0.3.0 // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect + github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect + github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect + github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect + github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect + github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect + github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect + github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect + github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect + github.com/tcnksm/go-httpstat v0.2.0 // indirect + github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect github.com/vishvananda/netns v0.0.4 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect + go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect golang.org/x/sync v0.10.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.24.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect + golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) + +//replace github.com/sagernet/sing => ../sing diff --git a/go.sum b/go.sum index 5b5b168d..7424346f 100644 --- a/go.sum +++ b/go.sum @@ -1,39 +1,69 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= -github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= +github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= +github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk= +github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= +github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc= +github.com/gaissmai/bart v0.11.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= +github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= +github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= +github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -41,26 +71,41 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= -github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= +github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/illarion/gonotify/v2 v2.0.3 h1:B6+SKPo/0Sw8cRJh1aLzNEeNVFfzE3c6N+o+vyxM+9A= +github.com/illarion/gonotify/v2 v2.0.3/go.mod h1:38oIJTgFqupkEydkkClkbL6i5lXV/bxdH9do5TALPEE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= -github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= +github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= +github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I= +github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= +github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ= github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE= github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054= @@ -70,32 +115,45 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= -github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= -github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= +github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= +github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= +github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= +github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= -github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= +github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= +github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 h1:qi+ijeREa0yfAaO+NOcZ81gv4uzOfALUIdhkiIFvmG4= github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1/go.mod h1:JULDuzTMn2gyZFcjpTVZP4/UuwAdbHJ0bum2RdjXojU= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= @@ -137,6 +195,8 @@ github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGT github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= +github.com/sagernet/tailscale v1.79.0-mod.1 h1:wIuAH7VqBYJNk0h2+bTyk4F0OlSqHvyLDCBrD3i+XNI= +github.com/sagernet/tailscale v1.79.0-mod.1/go.mod h1:RKY5WjYLj3JJ7VO/8ZCw8eAFa4+kWU6A1Ftdk84uB14= github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8= github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM= github.com/sagernet/wireguard-go v0.0.1-beta.5 h1:aBEsxJUMEONwOZqKPIkuAcv4zJV5p6XlzEN04CF0FXc= @@ -148,14 +208,36 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= +github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= +github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= +github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw= +github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= +github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= +github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= +github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= +github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= +github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU= +github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= +github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w= +github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU= +github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 h1:tdUdyPqJ0C97SJfjB9tW6EylTtreyee9C44de+UBG0g= +github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= +github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= +github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= +github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= +github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= +github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e h1:BA9O3BmlTmpjbvajAwzWx4Wo2TRVdpPXZEeemGQcajw= +github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= @@ -163,10 +245,13 @@ github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvv github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= +go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= @@ -174,18 +259,25 @@ golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -193,6 +285,7 @@ golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= @@ -202,21 +295,23 @@ golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -225,3 +320,5 @@ howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/include/registry.go b/include/registry.go index cbf793f4..866c506a 100644 --- a/include/registry.go +++ b/include/registry.go @@ -92,6 +92,7 @@ func EndpointRegistry() *endpoint.Registry { registry := endpoint.NewRegistry() registerWireGuardEndpoint(registry) + registerTailscaleEndpoint(registry) return registry } @@ -110,6 +111,7 @@ func DNSTransportRegistry() *dns.TransportRegistry { registerQUICTransports(registry) registerDHCPTransport(registry) + registerTailscaleTransport(registry) return registry } diff --git a/include/tailscale.go b/include/tailscale.go new file mode 100644 index 00000000..05eed2cd --- /dev/null +++ b/include/tailscale.go @@ -0,0 +1,17 @@ +//go:build with_tailscale + +package include + +import ( + "github.com/sagernet/sing-box/adapter/endpoint" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/protocol/tailscale" +) + +func registerTailscaleEndpoint(registry *endpoint.Registry) { + tailscale.RegisterEndpoint(registry) +} + +func registerTailscaleTransport(registry *dns.TransportRegistry) { + tailscale.RegistryTransport(registry) +} diff --git a/include/tailscale_stub.go b/include/tailscale_stub.go new file mode 100644 index 00000000..ddf6485e --- /dev/null +++ b/include/tailscale_stub.go @@ -0,0 +1,27 @@ +//go:build !with_tailscale + +package include + +import ( + "context" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/adapter/endpoint" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" +) + +func registerTailscaleEndpoint(registry *endpoint.Registry) { + endpoint.Register[option.TailscaleEndpointOptions](registry, C.TypeTailscale, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TailscaleEndpointOptions) (adapter.Endpoint, error) { + return nil, E.New(`Tailscale is not included in this build, rebuild with -tags with_tailscale`) + }) +} + +func registerTailscaleTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.TailscaleDNSServerOptions](registry, C.DNSTypeTailscale, func(ctx context.Context, logger log.ContextLogger, tag string, options option.TailscaleDNSServerOptions) (adapter.DNSTransport, error) { + return nil, E.New(`Tailscale is not included in this build, rebuild with -tags with_tailscale`) + }) +} diff --git a/mkdocs.yml b/mkdocs.yml index 5758525a..e1a74fb0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -93,6 +93,7 @@ nav: - Predefined: configuration/dns/server/predefined.md - DHCP: configuration/dns/server/dhcp.md - FakeIP: configuration/dns/server/fakeip.md + - Tailscale: configuration/dns/server/tailscale.md - DNS Rule: configuration/dns/rule.md - DNS Rule Action: configuration/dns/rule_action.md - FakeIP: configuration/dns/fakeip.md @@ -127,6 +128,7 @@ nav: - Endpoint: - configuration/endpoint/index.md - WireGuard: configuration/endpoint/wireguard.md + - Tailscale: configuration/endpoint/tailscale.md - Inbound: - configuration/inbound/index.md - Direct: configuration/inbound/direct.md diff --git a/option/tailscale.go b/option/tailscale.go new file mode 100644 index 00000000..30579fc7 --- /dev/null +++ b/option/tailscale.go @@ -0,0 +1,24 @@ +package option + +import ( + "net/netip" +) + +type TailscaleEndpointOptions struct { + DialerOptions + StateDirectory string `json:"state_directory,omitempty"` + AuthKey string `json:"auth_key,omitempty"` + ControlURL string `json:"control_url,omitempty"` + Ephemeral bool `json:"ephemeral,omitempty"` + Hostname string `json:"hostname,omitempty"` + ExitNode string `json:"exit_node,omitempty"` + ExitNodeAllowLANAccess bool `json:"exit_node_allow_lan_access,omitempty"` + AdvertiseRoutes []netip.Prefix `json:"advertise_routes,omitempty"` + AdvertiseExitNode bool `json:"advertise_exit_node,omitempty"` + UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"` +} + +type TailscaleDNSServerOptions struct { + Endpoint string `json:"endpoint,omitempty"` + AcceptDefaultResolvers bool `json:"accept_default_resolvers,omitempty"` +} diff --git a/protocol/tailscale/dns_transport.go b/protocol/tailscale/dns_transport.go new file mode 100644 index 00000000..0c83c698 --- /dev/null +++ b/protocol/tailscale/dns_transport.go @@ -0,0 +1,320 @@ +package tailscale + +import ( + "context" + "net" + "net/http" + "net/netip" + "net/url" + "os" + "reflect" + "strings" + "sync" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" + nDNS "github.com/sagernet/tailscale/net/dns" + "github.com/sagernet/tailscale/types/dnstype" + "github.com/sagernet/tailscale/wgengine/router" + "github.com/sagernet/tailscale/wgengine/wgcfg" + + mDNS "github.com/miekg/dns" + "go4.org/netipx" + "golang.org/x/net/http2" +) + +func RegistryTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.TailscaleDNSServerOptions](registry, C.DNSTypeTailscale, NewDNSTransport) +} + +type DNSTransport struct { + dns.TransportAdapter + ctx context.Context + logger logger.ContextLogger + endpointTag string + acceptDefaultResolvers bool + dnsRouter adapter.DNSRouter + endpointManager adapter.EndpointManager + cfg *wgcfg.Config + dnsCfg *nDNS.Config + endpoint *Endpoint + routePrefixes []netip.Prefix + routes map[string][]adapter.DNSTransport + hosts map[string][]netip.Addr + defaultResolvers []adapter.DNSTransport +} + +func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.TailscaleDNSServerOptions) (adapter.DNSTransport, error) { + if options.Endpoint == "" { + return nil, E.New("missing tailscale endpoint tag") + } + return &DNSTransport{ + TransportAdapter: dns.NewTransportAdapter(C.DNSTypeTailscale, tag, nil), + ctx: ctx, + logger: logger, + endpointTag: options.Endpoint, + acceptDefaultResolvers: options.AcceptDefaultResolvers, + dnsRouter: service.FromContext[adapter.DNSRouter](ctx), + endpointManager: service.FromContext[adapter.EndpointManager](ctx), + }, nil +} + +func (t *DNSTransport) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateInitialize { + return nil + } + rawOutbound, loaded := t.endpointManager.Get(t.endpointTag) + if !loaded { + return E.New("endpoint not found: ", t.endpointTag) + } + ep, isTailscale := rawOutbound.(*Endpoint) + if !isTailscale { + return E.New("endpoint is not Tailscale: ", t.endpointTag) + } + if ep.onReconfig != nil { + return E.New("only one Tailscale DNS server is allowed for single endpoint") + } + ep.onReconfig = t.onReconfig + t.endpoint = ep + return nil +} + +func (t *DNSTransport) Reset() { +} + +func (t *DNSTransport) onReconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCfg *nDNS.Config) { + if cfg == nil || dnsCfg == nil { + return + } + if (t.cfg != nil && reflect.DeepEqual(t.cfg, cfg)) && (t.dnsCfg != nil && reflect.DeepEqual(t.dnsCfg, dnsCfg)) { + return + } + t.cfg = cfg + t.dnsCfg = dnsCfg + err := t.updateDNSServers(routerCfg, dnsCfg) + if err != nil { + t.logger.Error(E.Cause(err, "update DNS servers")) + } +} + +func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *nDNS.Config) error { + t.routePrefixes = buildRoutePrefixes(routeConfig) + directDialerOnce := sync.OnceValue(func() N.Dialer { + directDialer := common.Must1(dialer.NewDefault(t.ctx, option.DialerOptions{})) + return &DNSDialer{transport: t, fallbackDialer: directDialer} + }) + routes := make(map[string][]adapter.DNSTransport) + for domain, resolvers := range dnsConfig.Routes { + var myResolvers []adapter.DNSTransport + for _, resolver := range resolvers { + myResolver, err := t.createResolver(directDialerOnce, resolver) + if err != nil { + return err + } + myResolvers = append(myResolvers, myResolver) + } + routes[domain.WithTrailingDot()] = myResolvers + } + hosts := make(map[string][]netip.Addr) + for domain, addresses := range dnsConfig.Hosts { + hosts[domain.WithTrailingDot()] = addresses + } + var defaultResolvers []adapter.DNSTransport + for _, resolver := range dnsConfig.DefaultResolvers { + myResolver, err := t.createResolver(directDialerOnce, resolver) + if err != nil { + return err + } + defaultResolvers = append(defaultResolvers, myResolver) + } + t.routes = routes + t.hosts = hosts + t.defaultResolvers = defaultResolvers + if len(defaultResolvers) > 0 { + t.logger.Info("updated ", len(routes), " routes, ", len(hosts), " hosts, default resolvers: ", + strings.Join(common.Map(dnsConfig.DefaultResolvers, func(it *dnstype.Resolver) string { return it.Addr }), " ")) + } else { + t.logger.Info("updated ", len(routes), " routes, ", len(hosts), " hosts") + } + return nil +} + +func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dnstype.Resolver) (adapter.DNSTransport, error) { + serverURL, parseURLErr := url.Parse(resolver.Addr) + var myDialer N.Dialer + if parseURLErr == nil && serverURL.Scheme == "http" { + myDialer = t.endpoint + } else { + myDialer = directDialer() + } + if len(resolver.BootstrapResolution) > 0 { + bootstrapTransport := transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, M.SocksaddrFrom(resolver.BootstrapResolution[0], 53)) + myDialer = dialer.NewResolveDialer(t.ctx, myDialer, false, "", adapter.DNSQueryOptions{Transport: bootstrapTransport}, 0) + } + if serverAddr := M.ParseSocksaddr(resolver.Addr); serverAddr.IsValid() { + if serverAddr.Port == 0 { + serverAddr.Port = 53 + } + return transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, serverAddr), nil + } else if parseURLErr != nil { + return nil, E.Cause(parseURLErr, "parse resolver address") + } else { + switch serverURL.Scheme { + case "https": + serverAddr = M.ParseSocksaddrHostPortStr(serverURL.Hostname(), serverURL.Port()) + if serverAddr.Port == 0 { + serverAddr.Port = 443 + } + tlsConfig := common.Must1(tls.NewClient(t.ctx, serverAddr.AddrString(), option.OutboundTLSOptions{ + ALPN: []string{http2.NextProtoTLS, "http/1.1"}, + })) + return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, tlsConfig), nil + case "http": + serverAddr = M.ParseSocksaddrHostPortStr(serverURL.Hostname(), serverURL.Port()) + if serverAddr.Port == 0 { + serverAddr.Port = 80 + } + return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, nil), nil + // case "tls": + default: + return nil, E.New("unknown resolver scheme: ", serverURL.Scheme) + } + } +} + +func buildRoutePrefixes(routeConfig *router.Config) []netip.Prefix { + var builder netipx.IPSetBuilder + for _, localAddr := range routeConfig.LocalAddrs { + builder.AddPrefix(localAddr) + } + for _, route := range routeConfig.Routes { + builder.AddPrefix(route) + } + for _, route := range routeConfig.LocalRoutes { + builder.AddPrefix(route) + } + for _, route := range routeConfig.SubnetRoutes { + builder.AddPrefix(route) + } + ipSet, err := builder.IPSet() + if err != nil { + return nil + } + return ipSet.Prefixes() +} + +func (t *DNSTransport) Close() error { + return nil +} + +func (t *DNSTransport) Raw() bool { + return true +} + +func (t *DNSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + if len(message.Question) != 1 { + return nil, os.ErrInvalid + } + question := message.Question[0] + addresses, hostsLoaded := t.hosts[question.Name] + if hostsLoaded { + switch question.Qtype { + case mDNS.TypeA: + addresses4 := common.Filter(addresses, func(addr netip.Addr) bool { + return addr.Is4() + }) + if len(addresses4) > 0 { + return dns.FixedResponse(message.Id, question, addresses4, C.DefaultDNSTTL), nil + } + case mDNS.TypeAAAA: + addresses6 := common.Filter(addresses, func(addr netip.Addr) bool { + return addr.Is6() + }) + if len(addresses6) > 0 { + return dns.FixedResponse(message.Id, question, addresses6, C.DefaultDNSTTL), nil + } + } + } + for domainSuffix, transports := range t.routes { + if strings.HasSuffix(question.Name, domainSuffix) { + if len(transports) == 0 { + return &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeNameError, + Response: true, + }, + Question: []mDNS.Question{question}, + }, nil + } + var lastErr error + for _, dnsTransport := range transports { + response, err := dnsTransport.Exchange(ctx, message) + if err != nil { + lastErr = err + continue + } + return response, nil + } + return nil, lastErr + } + } + if t.acceptDefaultResolvers { + if len(t.defaultResolvers) > 0 { + var lastErr error + for _, resolver := range t.defaultResolvers { + response, err := resolver.Exchange(ctx, message) + if err != nil { + lastErr = err + continue + } + return response, nil + } + return nil, lastErr + } else { + return nil, E.New("missing default resolvers") + } + } + return nil, dns.RCodeNameError +} + +type DNSDialer struct { + transport *DNSTransport + fallbackDialer N.Dialer +} + +func (d *DNSDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + if destination.IsFqdn() { + panic("invalid request here") + } + for _, prefix := range d.transport.routePrefixes { + if prefix.Contains(destination.Addr) { + return d.transport.endpoint.DialContext(ctx, network, destination) + } + } + return d.fallbackDialer.DialContext(ctx, network, destination) +} + +func (d *DNSDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + if destination.IsFqdn() { + panic("invalid request here") + } + for _, prefix := range d.transport.routePrefixes { + if prefix.Contains(destination.Addr) { + return d.transport.endpoint.ListenPacket(ctx, destination) + } + } + return d.fallbackDialer.ListenPacket(ctx, destination) +} diff --git a/protocol/tailscale/endpoint.go b/protocol/tailscale/endpoint.go new file mode 100644 index 00000000..6c2c111b --- /dev/null +++ b/protocol/tailscale/endpoint.go @@ -0,0 +1,473 @@ +package tailscale + +import ( + "context" + "fmt" + "net" + "net/netip" + "net/url" + "os" + "path/filepath" + "runtime" + "strings" + "sync/atomic" + "syscall" + "time" + + "github.com/sagernet/gvisor/pkg/tcpip" + "github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet" + "github.com/sagernet/gvisor/pkg/tcpip/header" + "github.com/sagernet/gvisor/pkg/tcpip/stack" + "github.com/sagernet/gvisor/pkg/tcpip/transport/tcp" + "github.com/sagernet/gvisor/pkg/tcpip/transport/udp" + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/adapter/endpoint" + "github.com/sagernet/sing-box/common/dialer" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/libbox/platform" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-tun" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/control" + E "github.com/sagernet/sing/common/exceptions" + F "github.com/sagernet/sing/common/format" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" + "github.com/sagernet/sing/service/filemanager" + "github.com/sagernet/tailscale/ipn" + "github.com/sagernet/tailscale/net/netmon" + "github.com/sagernet/tailscale/net/tsaddr" + "github.com/sagernet/tailscale/tsnet" + "github.com/sagernet/tailscale/types/ipproto" + "github.com/sagernet/tailscale/version" + "github.com/sagernet/tailscale/wgengine" + "github.com/sagernet/tailscale/wgengine/filter" +) + +func init() { + version.SetVersion("sing-box " + C.Version) +} + +func RegisterEndpoint(registry *endpoint.Registry) { + endpoint.Register[option.TailscaleEndpointOptions](registry, C.TypeTailscale, NewEndpoint) +} + +type Endpoint struct { + endpoint.Adapter + ctx context.Context + router adapter.Router + logger logger.ContextLogger + dnsRouter adapter.DNSRouter + network adapter.NetworkManager + platformInterface platform.Interface + server *tsnet.Server + stack *stack.Stack + filter *atomic.Pointer[filter.Filter] + onReconfig wgengine.ReconfigListener + + exitNode string + exitNodeAllowLANAccess bool + advertiseRoutes []netip.Prefix + advertiseExitNode bool + + udpTimeout time.Duration +} + +func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TailscaleEndpointOptions) (adapter.Endpoint, error) { + stateDirectory := options.StateDirectory + if stateDirectory == "" { + stateDirectory = "tailscale" + } + hostname := options.Hostname + if hostname == "" { + osHostname, _ := os.Hostname() + osHostname = strings.TrimSpace(osHostname) + hostname = osHostname + } + if hostname == "" { + hostname = "sing-box" + } + stateDirectory = filemanager.BasePath(ctx, os.ExpandEnv(stateDirectory)) + stateDirectory, _ = filepath.Abs(stateDirectory) + for _, advertiseRoute := range options.AdvertiseRoutes { + if advertiseRoute.Addr().IsUnspecified() && advertiseRoute.Bits() == 0 { + return nil, E.New("`advertise_routes` cannot be default, use `advertise_exit_node` instead.") + } + } + if options.AdvertiseExitNode && options.ExitNode != "" { + return nil, E.New("cannot advertise an exit node and use an exit node at the same time.") + } + var udpTimeout time.Duration + if options.UDPTimeout != 0 { + udpTimeout = time.Duration(options.UDPTimeout) + } else { + udpTimeout = C.UDPTimeout + } + var remoteIsDomain bool + if options.ControlURL != "" { + controlURL, err := url.Parse(options.ControlURL) + if err != nil { + return nil, E.Cause(err, "parse control URL") + } + remoteIsDomain = M.IsDomainName(controlURL.Hostname()) + } else { + // controlplane.tailscale.com + remoteIsDomain = true + } + outboundDialer, err := dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.DialerOptions, + RemoteIsDomain: remoteIsDomain, + ResolverOnDetour: true, + NewDialer: true, + }) + if err != nil { + return nil, err + } + dnsRouter := service.FromContext[adapter.DNSRouter](ctx) + server := &tsnet.Server{ + Dir: stateDirectory, + Hostname: hostname, + Logf: func(format string, args ...any) { + logger.Trace(fmt.Sprintf(format, args...)) + }, + UserLogf: func(format string, args ...any) { + logger.Debug(fmt.Sprintf(format, args...)) + }, + Ephemeral: options.Ephemeral, + AuthKey: options.AuthKey, + ControlURL: options.ControlURL, + Dialer: &endpointDialer{Dialer: outboundDialer, logger: logger}, + LookupHook: func(ctx context.Context, host string) ([]netip.Addr, error) { + return dnsRouter.Lookup(ctx, host, outboundDialer.(dialer.ResolveDialer).QueryOptions()) + }, + } + return &Endpoint{ + Adapter: endpoint.NewAdapter(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP}, nil), + ctx: ctx, + router: router, + logger: logger, + dnsRouter: dnsRouter, + network: service.FromContext[adapter.NetworkManager](ctx), + platformInterface: service.FromContext[platform.Interface](ctx), + server: server, + exitNode: options.ExitNode, + exitNodeAllowLANAccess: options.ExitNodeAllowLANAccess, + advertiseRoutes: options.AdvertiseRoutes, + advertiseExitNode: options.AdvertiseExitNode, + udpTimeout: udpTimeout, + }, nil +} + +func (t *Endpoint) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + if t.platformInterface != nil { + err := t.network.UpdateInterfaces() + if err != nil { + return err + } + netmon.RegisterInterfaceGetter(func() ([]netmon.Interface, error) { + return common.Map(t.network.InterfaceFinder().Interfaces(), func(it control.Interface) netmon.Interface { + return netmon.Interface{ + Interface: &net.Interface{ + Index: it.Index, + MTU: it.MTU, + Name: it.Name, + HardwareAddr: it.HardwareAddr, + Flags: it.Flags, + }, + AltAddrs: common.Map(it.Addresses, func(it netip.Prefix) net.Addr { + return &net.IPNet{ + IP: it.Addr().AsSlice(), + Mask: net.CIDRMask(it.Bits(), it.Addr().BitLen()), + } + }), + } + }), nil + }) + if runtime.GOOS == "android" { + setAndroidProtectFunc(t.platformInterface) + } + } + err := t.server.Start() + if err != nil { + return err + } + if t.onReconfig != nil { + t.server.ExportLocalBackend().ExportEngine().(wgengine.ExportedUserspaceEngine).SetOnReconfigListener(t.onReconfig) + } + + ipStack := t.server.ExportNetstack().ExportIPStack() + ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(t.ctx, ipStack, t).HandlePacket) + udpForwarder := tun.NewUDPForwarder(t.ctx, ipStack, t, t.udpTimeout) + ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket) + t.stack = ipStack + + localBackend := t.server.ExportLocalBackend() + perfs := &ipn.MaskedPrefs{ + ExitNodeIPSet: true, + AdvertiseRoutesSet: true, + } + if len(t.advertiseRoutes) > 0 { + perfs.AdvertiseRoutes = t.advertiseRoutes + } + if t.advertiseExitNode { + perfs.AdvertiseRoutes = append(perfs.AdvertiseRoutes, tsaddr.ExitRoutes()...) + } + _, err = localBackend.EditPrefs(perfs) + if err != nil { + return E.Cause(err, "update prefs") + } + t.filter = localBackend.ExportFilter() + + go t.watchState() + return nil +} + +func (t *Endpoint) watchState() { + localBackend := t.server.ExportLocalBackend() + localBackend.WatchNotifications(t.ctx, ipn.NotifyInitialState, nil, func(roNotify *ipn.Notify) (keepGoing bool) { + if roNotify.State != nil && *roNotify.State != ipn.NeedsLogin && *roNotify.State != ipn.NoState { + return false + } + authURL := localBackend.StatusWithoutPeers().AuthURL + if authURL != "" { + t.logger.Info("Waiting for authentication: ", authURL) + if t.platformInterface != nil { + err := t.platformInterface.SendNotification(&platform.Notification{ + Identifier: "tailscale-authentication", + TypeName: "Tailscale Authentication Notifications", + TypeID: 10, + Title: "Tailscale Authentication", + Body: F.ToString("Tailscale outbound[", t.Tag(), "] is waiting for authentication."), + OpenURL: authURL, + }) + if err != nil { + t.logger.Error("send authentication notification: ", err) + } + } + return false + } + return true + }) + if t.exitNode != "" { + localBackend.WatchNotifications(t.ctx, ipn.NotifyInitialState, nil, func(roNotify *ipn.Notify) (keepGoing bool) { + if roNotify.State == nil || *roNotify.State != ipn.Running { + return true + } + status, err := common.Must1(t.server.LocalClient()).Status(t.ctx) + if err != nil { + t.logger.Error("set exit node: ", err) + return + } + perfs := &ipn.MaskedPrefs{ + Prefs: ipn.Prefs{ + ExitNodeAllowLANAccess: t.exitNodeAllowLANAccess, + }, + ExitNodeIPSet: true, + ExitNodeAllowLANAccessSet: true, + } + err = perfs.SetExitNodeIP(t.exitNode, status) + if err != nil { + t.logger.Error("set exit node: ", err) + return true + } + _, err = localBackend.EditPrefs(perfs) + if err != nil { + t.logger.Error("set exit node: ", err) + return true + } + return false + }) + } +} + +func (t *Endpoint) Close() error { + netmon.RegisterInterfaceGetter(nil) + if runtime.GOOS == "android" { + setAndroidProtectFunc(nil) + } + return common.Close(common.PtrOrNil(t.server)) +} + +func (t *Endpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + switch network { + case N.NetworkTCP: + t.logger.InfoContext(ctx, "outbound connection to ", destination) + case N.NetworkUDP: + t.logger.InfoContext(ctx, "outbound packet connection to ", destination) + } + if destination.IsFqdn() { + destinationAddresses, err := t.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) + if err != nil { + return nil, err + } + return N.DialSerial(ctx, t, network, destination, destinationAddresses) + } + addr := tcpip.FullAddress{ + NIC: 1, + Port: destination.Port, + Addr: addressFromAddr(destination.Addr), + } + var networkProtocol tcpip.NetworkProtocolNumber + if destination.IsIPv4() { + networkProtocol = header.IPv4ProtocolNumber + } else { + networkProtocol = header.IPv6ProtocolNumber + } + switch N.NetworkName(network) { + case N.NetworkTCP: + tcpConn, err := gonet.DialContextTCP(ctx, t.stack, addr, networkProtocol) + if err != nil { + return nil, err + } + return tcpConn, nil + case N.NetworkUDP: + udpConn, err := gonet.DialUDP(t.stack, nil, &addr, networkProtocol) + if err != nil { + return nil, err + } + return udpConn, nil + default: + return nil, E.Extend(N.ErrUnknownNetwork, network) + } +} + +func (t *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + t.logger.InfoContext(ctx, "outbound packet connection to ", destination) + if destination.IsFqdn() { + destinationAddresses, err := t.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) + if err != nil { + return nil, err + } + packetConn, _, err := N.ListenSerial(ctx, t, destination, destinationAddresses) + if err != nil { + return nil, err + } + return packetConn, err + } + addr4, addr6 := t.server.TailscaleIPs() + bind := tcpip.FullAddress{ + NIC: 1, + } + var networkProtocol tcpip.NetworkProtocolNumber + if destination.IsIPv4() { + if !addr4.IsValid() { + return nil, E.New("missing Tailscale IPv4 address") + } + networkProtocol = header.IPv4ProtocolNumber + bind.Addr = addressFromAddr(addr4) + } else { + if !addr6.IsValid() { + return nil, E.New("missing Tailscale IPv6 address") + } + networkProtocol = header.IPv6ProtocolNumber + bind.Addr = addressFromAddr(addr6) + } + udpConn, err := gonet.DialUDP(t.stack, &bind, nil, networkProtocol) + if err != nil { + return nil, err + } + return udpConn, nil +} + +func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error { + tsFilter := t.filter.Load() + if tsFilter != nil { + var ipProto ipproto.Proto + switch N.NetworkName(network) { + case N.NetworkTCP: + ipProto = ipproto.TCP + case N.NetworkUDP: + ipProto = ipproto.UDP + } + response := tsFilter.Check(source.Addr, destination.Addr, destination.Port, ipProto) + switch response { + case filter.Drop: + return syscall.ECONNRESET + case filter.DropSilently: + return tun.ErrDrop + } + } + return t.router.PreMatch(adapter.InboundContext{ + Inbound: t.Tag(), + InboundType: t.Type(), + Network: network, + Source: source, + Destination: destination, + }) +} + +func (t *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { + var metadata adapter.InboundContext + metadata.Inbound = t.Tag() + metadata.InboundType = t.Type() + metadata.Source = source + addr4, addr6 := t.server.TailscaleIPs() + switch destination.Addr { + case addr4: + destination.Addr = netip.AddrFrom4([4]uint8{127, 0, 0, 1}) + case addr6: + destination.Addr = netip.IPv6Loopback() + } + metadata.Destination = destination + t.logger.InfoContext(ctx, "inbound connection from ", source) + t.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) + t.router.RouteConnectionEx(ctx, conn, metadata, onClose) +} + +func (t *Endpoint) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { + var metadata adapter.InboundContext + metadata.Inbound = t.Tag() + metadata.InboundType = t.Type() + metadata.Source = source + metadata.Destination = destination + addr4, addr6 := t.server.TailscaleIPs() + switch destination.Addr { + case addr4: + metadata.OriginDestination = destination + destination.Addr = netip.AddrFrom4([4]uint8{127, 0, 0, 1}) + conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination) + case addr6: + metadata.OriginDestination = destination + destination.Addr = netip.IPv6Loopback() + conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination) + } + t.logger.InfoContext(ctx, "inbound packet connection from ", source) + t.logger.InfoContext(ctx, "inbound packet connection to ", destination) + t.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose) +} + +func addressFromAddr(destination netip.Addr) tcpip.Address { + if destination.Is6() { + return tcpip.AddrFrom16(destination.As16()) + } else { + return tcpip.AddrFrom4(destination.As4()) + } +} + +type endpointDialer struct { + N.Dialer + logger logger.ContextLogger +} + +func (d *endpointDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + switch N.NetworkName(network) { + case N.NetworkTCP: + d.logger.InfoContext(ctx, "output connection to ", destination) + case N.NetworkUDP: + d.logger.InfoContext(ctx, "output packet connection to ", destination) + } + return d.Dialer.DialContext(ctx, network, destination) +} + +func (d *endpointDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + d.logger.InfoContext(ctx, "output packet connection") + return d.Dialer.ListenPacket(ctx, destination) +} diff --git a/protocol/tailscale/protect_android.go b/protocol/tailscale/protect_android.go new file mode 100644 index 00000000..90ab615a --- /dev/null +++ b/protocol/tailscale/protect_android.go @@ -0,0 +1,16 @@ +package tailscale + +import ( + "github.com/sagernet/sing-box/experimental/libbox/platform" + "github.com/sagernet/tailscale/net/netns" +) + +func setAndroidProtectFunc(platformInterface platform.Interface) { + if platformInterface != nil { + netns.SetAndroidProtectFunc(func(fd int) error { + return platformInterface.AutoDetectInterfaceControl(fd) + }) + } else { + netns.SetAndroidProtectFunc(nil) + } +} diff --git a/protocol/tailscale/protect_nonandroid.go b/protocol/tailscale/protect_nonandroid.go new file mode 100644 index 00000000..eeb56bf6 --- /dev/null +++ b/protocol/tailscale/protect_nonandroid.go @@ -0,0 +1,8 @@ +//go:build !android + +package tailscale + +import "github.com/sagernet/sing-box/experimental/libbox/platform" + +func setAndroidProtectFunc(platformInterface platform.Interface) { +} From 70107973ae616b81ef68d900cd58f5ce4975b082 Mon Sep 17 00:00:00 2001 From: xchacha20-poly1305 Date: Wed, 12 Feb 2025 20:56:41 +0800 Subject: [PATCH 48/62] Remove single quotes of raw Moziila certs --- cmd/internal/update_certificates/main.go | 5 +- common/certificate/mozilla.go | 785 ++++++++++++----------- 2 files changed, 414 insertions(+), 376 deletions(-) diff --git a/cmd/internal/update_certificates/main.go b/cmd/internal/update_certificates/main.go index cf597c86..744d7724 100644 --- a/cmd/internal/update_certificates/main.go +++ b/cmd/internal/update_certificates/main.go @@ -60,7 +60,10 @@ func init() { generated.WriteString(record[nameIndex]) generated.WriteString("\n") generated.WriteString(" mozillaIncluded.AppendCertsFromPEM([]byte(`") - generated.WriteString(record[certIndex]) + cert := record[certIndex] + // Remove single quotes + cert = cert[1 : len(cert)-1] + generated.WriteString(cert) generated.WriteString("`))\n") } generated.WriteString("}\n") diff --git a/common/certificate/mozilla.go b/common/certificate/mozilla.go index 3bf1d175..097091d0 100644 --- a/common/certificate/mozilla.go +++ b/common/certificate/mozilla.go @@ -10,7 +10,7 @@ func init() { mozillaIncluded = x509.NewCertPool() // Actalis Authentication Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 @@ -42,10 +42,10 @@ K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TunTrust Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv @@ -77,10 +77,10 @@ nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Amazon Root CA 1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL @@ -99,10 +99,10 @@ N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Amazon Root CA 2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL @@ -132,10 +132,10 @@ n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE 76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H 9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT 4PsJYGw= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Amazon Root CA 3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG @@ -146,10 +146,10 @@ QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM YyRIHN8wfdVoOw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Amazon Root CA 4 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG @@ -161,10 +161,10 @@ M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW 1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Starfield Services Root Certificate Authority - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs @@ -187,10 +187,10 @@ qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certum CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM @@ -208,10 +208,10 @@ xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certum EC-384 CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT @@ -225,10 +225,10 @@ QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certum Trusted Network CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU @@ -249,10 +249,10 @@ I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certum Trusted Network CA 2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG @@ -285,10 +285,10 @@ b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P 5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi DrW5viSP ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certum Trusted Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV @@ -320,10 +320,10 @@ P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP 0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Autoridad de Certificacion Firmaprofesional CIF A62634068 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 @@ -357,10 +357,10 @@ CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // FIRMAPROFESIONAL CA ROOT-A WEB - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB @@ -375,10 +375,10 @@ BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG XSaQpYXFuXqUPoeovQA= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // ANF Secure Server Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV @@ -411,10 +411,10 @@ OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ +PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Buypass Class 2 Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow @@ -444,10 +444,10 @@ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Buypass Class 3 Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow @@ -477,10 +477,10 @@ kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certainly Root E1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ @@ -492,10 +492,10 @@ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certainly Root R1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 @@ -525,10 +525,10 @@ Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 OV+KmalBWQewLK8= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certigna - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ @@ -549,10 +549,10 @@ fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Certigna Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x @@ -587,10 +587,10 @@ faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw 3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // certSIGN ROOT CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP @@ -609,10 +609,10 @@ MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // certSIGN ROOT CA G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ @@ -642,10 +642,10 @@ pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE 1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX QRBdJ3NghVdJIgc= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // ePKI Root Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe @@ -677,10 +677,10 @@ o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // HiPKI Root CA - G1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa @@ -710,10 +710,10 @@ Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // CommScope Public Trust ECC Root-01 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa @@ -726,10 +726,10 @@ VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg 2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS Um9poIyNStDuiw7LR47QjRE= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // CommScope Public Trust ECC Root-02 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa @@ -742,10 +742,10 @@ VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV mkzw5l4lIhVtwodZ0LKOag== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // CommScope Public Trust RSA Root-01 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1 @@ -775,10 +775,10 @@ Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // CommScope Public Trust RSA Root-02 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2 @@ -808,10 +808,10 @@ PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670 v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SecureSign Root CA12 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw @@ -831,10 +831,10 @@ mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA 8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV 55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/ yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SecureSign Root CA14 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw @@ -865,10 +865,10 @@ dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB 365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c JRNItX+S ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SecureSign Root CA15 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy @@ -881,10 +881,10 @@ Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT 9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp 4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6 bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // D-TRUST BR Root CA 1 2020 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 @@ -901,10 +901,45 @@ c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV dWNbFJWcHwHP2NVypw87 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) + + // D-TRUST BR Root CA 2 2023 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBI +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE +LVRSVVNUIEJSIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUw +OTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi +MCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCTcfKr +i3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNE +gXtRr90zsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8 +k12b9py0i4a6Ibn08OhZWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCT +Rphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl +2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LULQyReS2tNZ9/WtT5PeB+U +cSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIvx9gvdhFP +/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bS +uREVMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+ +0bpwHJwh5Q8xaRfX/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4N +DfTisl01gLmB1IRpkQLLddCNxbU9CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+ +XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZ5Dw1t61 +GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tI +FoE9c+CeJyrrd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67n +riv6uvw8l5VAk1/DLQOj7aRvU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTR +VFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4nj8+AybmTNudX0KEPUUDAxxZiMrc +LmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdijYQ6qgYF/6FKC0ULn +4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff/vtD +hQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsG +koHU6XCPpz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46 +ls/pdu4D58JDUjxqgejBWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aS +Ecr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/5usWDiJFAbzdNpQ0qTUmiteXue4Icr80 +knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jtn/mtd+ArY0+ew+43u3gJ +hJ65bvspmZDogNOfJA== +-----END CERTIFICATE-----`)) // D-TRUST EV Root CA 1 2020 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 @@ -921,10 +956,45 @@ c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb gfM0agPnIjhQW+0ZT0MW ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) + + // D-TRUST EV Root CA 2 2023 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBI +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE +LVRSVVNUIEVWIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUw +OTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi +MCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1sJkK +F8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE +7CUXFId/MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFe +EMbsh2aJgWi6zCudR3Mfvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6 +lHPTGGkKSv/BAQP/eX+1SH977ugpbzZMlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIb +RlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3YG14C8qKXO0elg6DpkiV +jTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq9107PncjLgc +jmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZx +TnXonMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ +ARZZaBhDM7DS3LAaQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nk +hbDhezGdpn9yo7nELC7MmVcOIQxFAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knF +NXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqvyREBuH +kV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14 +QvBukEdHjqOSMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4 +pZt+UPJ26oUFKidBK7GB0aL2QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q +3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xDUmPBEcrCRbH0O1P1aa4846XerOhU +t7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V4U/M5d40VxDJI3IX +cI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuodNv8 +ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT +2vFp4LJiTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs +7dpn1mKmS00PaaLJvOwiS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNP +gofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAst +Nl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L+KIkBI3Y4WNeApI02phh +XBxvWHZks/wCuPWdCg== +-----END CERTIFICATE-----`)) // D-TRUST Root CA 3 2013 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEDjCCAvagAwIBAgIDD92sMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD QSAzIDIwMTMwHhcNMTMwOTIwMDgyNTUxWhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD @@ -947,10 +1017,10 @@ t4RVLFzI9XRKEBmLo8ftNdYJSNMOwLo5qLBGArDbxohZwr78e7Erz35ih1WWzAFv m2chlTWL+BD8cRu3SzdppjvW7IvuwbDzJcmPkn2h6sPKRL8mpXSSnON065102ctN h9j8tGlsi6BDB2B4l+nZk3zCRrybN1Kj7Yo8E6l7U0tJmhEFLAtuVqwfLoJs4Gln tQ5tLdnkwBXxP/oYcuEVbSdbLTAoK59ImmQrme/ydUlfXA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // D-TRUST Root Class 3 CA 2 2009 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha @@ -974,10 +1044,10 @@ o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // D-TRUST Root Class 3 CA 2 EV 2009 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw @@ -1001,10 +1071,10 @@ nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // D-Trust SBR Root CA 1 2022 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICXjCCAeOgAwIBAgIQUs/kjG2gSvc/gpcMgAmMlTAKBggqhkjOPQQDAzBJMQsw CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSMwIQYDVQQDExpELVRy dXN0IFNCUiBSb290IENBIDEgMjAyMjAeFw0yMjA3MDYxMTMwMDBaFw0zNzA3MDYx @@ -1018,10 +1088,10 @@ hjlodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Nicl9yb290X2Nh XzFfMjAyMi5jcmwwCgYIKoZIzj0EAwMDaQAwZgIxAJf53q5Lj5i1HkB/Mn1NVEPa ic3CqpI80YIec8/6TJIg+2MnxfVzPQk996dhhozzagIxAOcvfLj1JYw7OR82q431 hqIu4Xpk2mc5Av7+Mz/Zc7ZYWzr8sqTZYHh3zHmnpq5VvQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // D-Trust SBR Root CA 2 2022 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFrDCCA5SgAwIBAgIQVNWjlR49lbpyG5rQMSFKujANBgkqhkiG9w0BAQ0FADBJ MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSMwIQYDVQQDExpE LVRydXN0IFNCUiBSb290IENBIDIgMjAyMjAeFw0yMjA3MDcwNzMwMDBaFw0zNzA3 @@ -1053,10 +1123,10 @@ JpmgVDuhEm1wYs7T+bi9IvzUmtS74jgWL7d9OcKwqQPpnM9+GI123F8Ru+tC7FAJ PlzskDHYGnK6P2kH7pg0wjSk1toT1qmE8gCGwFS6HhGw4rnEB7SR56rmMVZvsUTE KmK8ybBlnDT8DBpT3yEXu8JtoQrm8bCqRAlQSTh6XXHiMS4ZsN+VQgR9hIjOCiNn azidFt4G/ihwOKVarvyD7Q== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // T-TeleSec GlobalRoot Class 2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl @@ -1078,10 +1148,10 @@ IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP BSeOE6Fuwg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // T-TeleSec GlobalRoot Class 3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl @@ -1103,10 +1173,10 @@ WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ 91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Telekom Security SMIME ECC Root 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICRzCCAc2gAwIBAgIQFSrdFMkY0aRWQIamJa8HXzAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH bWJIMS0wKwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIEVDQyBSb290IDIw @@ -1120,10 +1190,10 @@ vZA6SzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQD AwNoADBlAjEA1rxIkodHA8dwOyW2H65GZ3N0ACdL5KUEogPfXiitbl4DyN1onLa/ lBBIlS8P/xiLAjABQDOel5dNBfJ0VAzNOf1qawnBJD9hjjiht+jXRBURYv8OYTdH S0B/Sl+yZ1pzdcI= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Telekom Security SMIME RSA Root 2023 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgIQDH5i9XlzO51Djotj7ZGVuDANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 eSBHbWJIMS0wKwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIFJTQSBSb290 @@ -1155,10 +1225,10 @@ NDnPpZo2qsjtebzP9s4EUwvaslAjfLw+Jq3wDkO7JsuuwkDeNx8KoFHNY522T9jG R3y82LTtnovzEeKotT7srnA+fiK7NUgXYGIUkTCjdj2mUTaLHw3dajEcpe3dlqNu cg8TTaqnqVx4+QMSGJM3RRKJPfi+yr3ZvgzZGGSnyEE+dYIhOH1l9KDUE0sHeCn5 nX7Mhz/E2i6I3eML3FpRWunZEk+eAtv3BSVR ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Telekom Security TLS ECC Root 2020 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw @@ -1172,10 +1242,10 @@ MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn 27iQ7t0l ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Telekom Security TLS RSA Root 2023 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy @@ -1207,10 +1277,10 @@ L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Baltimore CyberTrust Root - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX @@ -1230,10 +1300,10 @@ jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Assured ID Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv @@ -1254,10 +1324,10 @@ fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Assured ID Root G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv @@ -1278,10 +1348,10 @@ lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Assured ID Root G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg @@ -1295,10 +1365,10 @@ BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Global Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD @@ -1319,10 +1389,10 @@ hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Global Root G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH @@ -1343,10 +1413,10 @@ Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Global Root G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe @@ -1360,10 +1430,10 @@ BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert High Assurance EV Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j @@ -1385,10 +1455,10 @@ hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert SMIME ECC P384 Root G5 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICHDCCAaOgAwIBAgIQBT9uoAYBcn3tP8OjtqPW7zAKBggqhkjOPQQDAzBQMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKDAmBgNVBAMTH0Rp Z2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN @@ -1401,10 +1471,10 @@ wmQyF/7gZ5AurTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggq hkjOPQQDAwNnADBkAjA3RPUygONx6/Rtz3zMkZrDbnHY0iNdkk2CQm1cYZX2kfWn CPZql+mclC2YcP0ztgkCMAc8L7lYgl4Po2Kok2fwIMNpvwMsO1CnO69BOMlSSJHW Dvu8YDB8ZD8SHkV/UT70pg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert SMIME RSA4096 Root G5 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFajCCA1KgAwIBAgIQBfa6BCODRst9XOa5W7ocVTANBgkqhkiG9w0BAQwFADBP MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJzAlBgNVBAMT HkRpZ2lDZXJ0IFNNSU1FIFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBa @@ -1434,10 +1504,10 @@ CQxy5BMjYEyjyhcue2cA29DN6nofOSZXiTB3y07llUVPX/s2XD35ILU6ECVPkzJa 7sGW6OlWBLBJYU3seKidGMH/2OovVu+VK3sEXmfjVUDtOQT5C3n1aoxcD4makMfN i97bJjWhbs2zQvKiDzsMjpP/FM/895P35EEIbhlSEQ9TGXN4DM/YhYH4rVXIsJ5G Y6+cUu5cv/DAWzceCSDSPiPGoRVKDjZ+MMV5arwiiNkMUkAf3U4PZyYW0q0XHA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert TLS ECC P384 Root G5 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 @@ -1450,10 +1520,10 @@ B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 DXZDjC5Ty3zfDBeWUA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert TLS RSA4096 Root G5 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN @@ -1483,10 +1553,10 @@ p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DigiCert Trusted Root G4 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg @@ -1517,10 +1587,10 @@ cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DIGITALSIGN GLOBAL ROOT ECDSA CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICajCCAfCgAwIBAgIUNi2PcoiiKCfkAP8kxi3k6/qdtuEwCgYIKoZIzj0EAwMw ZDELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmljYWRv cmEgRGlnaXRhbDEpMCcGA1UEAwwgRElHSVRBTFNJR04gR0xPQkFMIFJPT1QgRUNE @@ -1534,10 +1604,10 @@ GDAWgBTOr0qLGnXi8TjnAvAWrV7qZNV7tDAdBgNVHQ4EFgQUzq9Kixp14vE45wLw Fq1e6mTVe7QwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMAqIxHGc RANNjbTHvKiu2TAnNWprFmPX/OdZ4aeJG0wxmiNVRObzQyHVRydvbVcBqgIxAPuy 6uKXf1G1n0jrvG81iahkcKtXds3AxhRgyn/iggBz98w16o4km+UIWccEjHN4/g== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // DIGITALSIGN GLOBAL ROOT RSA CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIUXVnIyqsJV/XmtdoplARq/8XUlYcwDQYJKoZIhvcNAQEN BQAwYjELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmlj YWRvcmEgRGlnaXRhbDEnMCUGA1UEAwweRElHSVRBTFNJR04gR0xPQkFMIFJPT1Qg @@ -1569,10 +1639,10 @@ NrskGnkcUdH+E7v/eCzcpL4v9sVLU8+nTJlecKxZiASuZAS/e6Z6TdPod72hflAV 8+9JMIVNIVeq2yx1l62BAYeisXCdHgZaA2CxP6ZtgizUFLGBpeg9iB20cixYN4qO OJS4c92p4Lj2d6KzfFjermk6tYulGrvy2HQGnP1icyAhdrF+cJ4Z1OsXYhk4mc02 K0f+McvfueSsCNPYpuvUnn5LZKRVXSsXyQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // CA Disig Root R2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy @@ -1602,10 +1672,10 @@ gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GLOBALTRUST 2020 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx @@ -1636,10 +1706,10 @@ MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn 4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // emSign ECC Root CA - C3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw @@ -1652,10 +1722,10 @@ BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c 3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J 0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // emSign ECC Root CA - G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g @@ -1669,10 +1739,10 @@ zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD +JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // emSign Root CA - C1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw @@ -1692,10 +1762,10 @@ kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT +xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // emSign Root CA - G1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH @@ -1716,10 +1786,10 @@ GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH 6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx iN66zB+Afko= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AffirmTrust Commercial - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL @@ -1738,10 +1808,10 @@ vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AffirmTrust Networking - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL @@ -1760,10 +1830,10 @@ QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AffirmTrust Premium - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG @@ -1793,10 +1863,10 @@ YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AffirmTrust Premium ECC - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ @@ -1808,10 +1878,10 @@ A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Entrust Root Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW @@ -1837,10 +1907,10 @@ AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Entrust Root Certification Authority - EC1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu @@ -1857,10 +1927,10 @@ Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Entrust Root Certification Authority - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs @@ -1884,10 +1954,10 @@ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Entrust Root Certification Authority - G4 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg @@ -1922,10 +1992,10 @@ b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk 5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Entrust.net Certification Authority (2048) - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 @@ -1949,10 +2019,10 @@ zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Atos TrustedRoot 2011 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM @@ -1972,10 +2042,10 @@ DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Atos TrustedRoot Root CA ECC G2 2020 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICMTCCAbagAwIBAgIMC3MoERh0MBzvbwiEMAoGCCqGSM49BAMDMEsxCzAJBgNV BAYTAkRFMQ0wCwYDVQQKDARBdG9zMS0wKwYDVQQDDCRBdG9zIFRydXN0ZWRSb290 IFJvb3QgQ0EgRUNDIEcyIDIwMjAwHhcNMjAxMjE1MDgzOTEwWhcNNDAxMjEwMDgz @@ -1988,10 +2058,10 @@ shufvlwfjP2ztvuzDgmHMB0GA1UdDgQWBBRbH8RxbLIbn75cH4z9s7b7sw4JhzAO BgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAOzgmf3d5FTByx/oPijX FVlKgspTMOzrNqW5yM6TR1bIYabhbZJTlY/241VT8N165wIxALCH1RuzYPyRjYDK ohtRSzhUy6oee9flRJUWLzxEeC4luuqQ5OxS7lfsA4TzXtsWDQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Atos TrustedRoot Root CA ECC TLS 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 @@ -2004,10 +2074,10 @@ KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo 9H1/IISpQuQo ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Atos TrustedRoot Root CA RSA G2 2020 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFfzCCA2egAwIBAgIMR7opRlU+FpKXsKtAMA0GCSqGSIb3DQEBDAUAMEsxCzAJ BgNVBAYTAkRFMQ0wCwYDVQQKDARBdG9zMS0wKwYDVQQDDCRBdG9zIFRydXN0ZWRS b290IFJvb3QgQ0EgUlNBIEcyIDIwMjAwHhcNMjAxMjE1MDg0MTIzWhcNNDAxMjEw @@ -2038,10 +2108,10 @@ VD190nZ12V4+MkinjPKecgz4uFi4FyOlFId1WHoAgQciOWpMlKC1otunLMGw8aOb wEz3bXDqMZ/xrn0+cyjZod/6k/CbsPDizSUgde/ifTIFyZt27su9MR75lJhLJFhW SMDeBky9pjRd7RZhY3P7GeL6W9iXddRtnmA5XpSLAizrmc5gKm4bjKdLvP025pgf ZfJ/8eOPTIBGNli2oWXLzhxEdQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Atos TrustedRoot Root CA RSA TLS 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 @@ -2071,10 +2141,10 @@ AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx @@ -2105,26 +2175,10 @@ pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R 8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE-----'`)) - - // GlobalSign - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 @@ -2144,10 +2198,26 @@ jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) + + // GlobalSign + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE-----`)) // GlobalSign Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw @@ -2167,10 +2237,10 @@ yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign Root E46 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw @@ -2182,10 +2252,10 @@ yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ 7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 +RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign Root R46 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy @@ -2215,10 +2285,10 @@ u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP 4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign Secure Mail Root E45 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICITCCAaegAwIBAgIQdlP+qicdlUZd1vGe5biQCjAKBggqhkjOPQQDAzBSMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMf R2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IEU0NTAeFw0yMDAzMTgwMDAwMDBa @@ -2231,10 +2301,10 @@ DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3xNei1/CQAL9VreUTLYe1aaxFJYw CgYIKoZIzj0EAwMDaAAwZQIwE7C+13EgPuSrnM42En1fTB8qtWlFM1/TLVqy5IjH 3go2QjJ5naZruuH5RCp7isMSAjEAoGYcToedh8ntmUwbCu4tYMM3xx3NtXKw2cbv vPL/P/BS3QjnqmR5w+RpV5EvpMt8 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign Secure Mail Root R45 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIQdlP+qExQq5+NMrUdA49X3DANBgkqhkiG9w0BAQwFADBS MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UE AxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IFI0NTAeFw0yMDAzMTgwMDAw @@ -2265,10 +2335,10 @@ l+6NJllXu3jwelAwCbBgqp9O3Mk+HjrcYpMzsDpUdG8sMUXRaxEyamh29j32ahNe JJjn6h2az3iCB2D3TRDTgZpFjZ6vm9yAx0OylWikww7oCkcVv1Qz3AHn1aYec9h6 sr8vreNVMJ7fDkG84BH1oQyoIuHjAKNOcHyS4wTRekKKdZBZ45vRTKJkvXN5m2/y s8H2PA== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Go Daddy Class 2 Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 @@ -2291,10 +2361,10 @@ TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Go Daddy Root Certificate Authority - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp @@ -2316,10 +2386,10 @@ gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Starfield Class 2 Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw @@ -2342,10 +2412,10 @@ eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Starfield Root Certificate Authority - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs @@ -2367,10 +2437,10 @@ sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GlobalSign - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw @@ -2381,10 +2451,10 @@ uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ +wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GTS Root R1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw @@ -2414,10 +2484,10 @@ Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT 0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm 2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GTS Root R2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw @@ -2447,10 +2517,10 @@ TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV 7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl 6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GTS Root R3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw @@ -2462,10 +2532,10 @@ jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // GTS Root R4 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw @@ -2477,10 +2547,10 @@ HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D 9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Hongkong Post Root CA 3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n @@ -2513,10 +2583,10 @@ JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG mpv0 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // ACCVRAIZ1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ @@ -2559,10 +2629,10 @@ I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AC RAIZ FNMT-RCM - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ @@ -2593,10 +2663,10 @@ fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp 9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AC RAIZ FNMT-RCM SERVIDORES SEGUROS - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S @@ -2611,10 +2681,10 @@ VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy v+c= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Staat der Nederlanden Root CA - G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX @@ -2645,10 +2715,10 @@ fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq 1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM 94B7IWcnMFk= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w @@ -2673,10 +2743,10 @@ IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c 8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // HARICA Client ECC Root CA 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICWjCCAeGgAwIBAgIQMWjZ2OFiVx7SGUSI5hB98DAKBggqhkjOPQQDAzBvMQsw CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh cmNoIEluc3RpdHV0aW9ucyBDQTEnMCUGA1UEAwweSEFSSUNBIENsaWVudCBFQ0Mg @@ -2690,10 +2760,10 @@ AQH/BAUwAwEB/zAdBgNVHQ4EFgQUUgjSvjKBJf31GpfsTl8au1PNkK0wDgYDVR0P AQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMEwxRUZPqOa+w3eyGhhLLYh7WOar lGtEA7AX/9+Cc0RRLP2THQZ7FNKJ7EAM7yEBLgIwL8kuWmwsHdmV4J6wuVxSfPb4 OMou8dQd8qJJopX4wVheT/5zCu8xsKsjWBOMi947 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // HARICA Client RSA Root CA 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFqjCCA5KgAwIBAgIQVVL4HtsbJCyeu5YYzQIoPjANBgkqhkiG9w0BAQsFADBv MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEnMCUGA1UEAwweSEFSSUNBIENsaWVudCBS @@ -2725,10 +2795,10 @@ ndSV9ZmqRuqurL/0FBkk6Izs4/W8BmiKKgwFXwqXdafcfsD913oY3zDROEsfsJhw v8x8c/BuxDGlpJcdrL/ObCFKvicjZ/MGVoEKkY624QMFMyzaNAhNTlAjrR+lxdR6 /uoJ7KcoYItGfLXqm91P+edrFcaIz0Pb5SfcBFZub0YV8VYt6FwMc8MjgTggy8kM ac8sqzuEYDMZUv1pFDM= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // HARICA TLS ECC Root CA 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v @@ -2742,10 +2812,10 @@ AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // HARICA TLS RSA Root CA 2021 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg @@ -2777,10 +2847,10 @@ BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU 63ZTGI0RmLo= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Hellenic Academic and Research Institutions ECC RootCA 2015 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl @@ -2796,10 +2866,10 @@ MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Hellenic Academic and Research Institutions RootCA 2015 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT @@ -2833,10 +2903,10 @@ bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // IdenTrust Commercial Root CA 1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw @@ -2866,10 +2936,10 @@ l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG 4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A 7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // IdenTrust Public Sector Root CA 1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN @@ -2899,10 +2969,10 @@ WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv 8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // ISRG Root X1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 @@ -2932,10 +3002,10 @@ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // ISRG Root X2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 @@ -2948,10 +3018,10 @@ AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 /q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Izenpe.com - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD @@ -2984,10 +3054,10 @@ UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SZAFIR ROOT CA2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw @@ -3007,10 +3077,10 @@ nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // LAWtrust Root CA2 (4096) - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFmDCCA4CgAwIBAgIEVRpusTANBgkqhkiG9w0BAQsFADBDMQswCQYDVQQGEwJa QTERMA8GA1UEChMITEFXdHJ1c3QxITAfBgNVBAMTGExBV3RydXN0IFJvb3QgQ0Ey ICg0MDk2KTAgFw0yMzAyMTQwOTE5MzhaGA8yMDUzMDIxNDA5NDkzOFowQzELMAkG @@ -3041,10 +3111,10 @@ NAdigkz0fseHdA6wIR4JIIDBsxU9Rm3T8QaSP++glYocbncxtut4KQx77oKlT36k KV6eqi34jsDz/A0GhZtO3PfiCXzQFFEeerMjr/rRYSpltQHZuOMHyiR20vBKvu+G BIBCFXARaH7Xx7v+506bnJWlHEqkydAJjKrOSNIekpfXEentZsw33PXXG3SbpupC rF0y4Fj0gUf/0hLifhzcSXaWwx2fS8pcKjdbPYrROJsh2uO/RUPT4Fh3Hyg= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // e-Szigno Root CA 2017 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv @@ -3058,10 +3128,10 @@ A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ +efcMQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Microsec e-Szigno Root CA 2009 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G @@ -3084,10 +3154,10 @@ ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Microsoft ECC Root Certificate Authority 2017 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw @@ -3101,10 +3171,10 @@ BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Microsoft RSA Root Certificate Authority 2017 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 @@ -3136,10 +3206,10 @@ GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB RA+GsCyRxj3qrg+E ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // NAVER Global Root Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 @@ -3171,10 +3241,10 @@ LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX 5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul 9XXeifdy ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // NetLock Arany (Class Gold) Főtanúsítvány - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl @@ -3197,10 +3267,10 @@ bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // OISTE WISeKey Global Root GA CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl @@ -3223,10 +3293,10 @@ vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ /L7fCg0= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // OISTE WISeKey Global Root GB CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i @@ -3247,10 +3317,10 @@ gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // OISTE WISeKey Global Root GC CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg @@ -3264,10 +3334,10 @@ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV 57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // QuoVadis Root CA 1 G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 @@ -3297,10 +3367,10 @@ NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // QuoVadis Root CA 2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV @@ -3332,10 +3402,10 @@ mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // QuoVadis Root CA 2 G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 @@ -3365,10 +3435,10 @@ dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // QuoVadis Root CA 3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV @@ -3405,10 +3475,10 @@ zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // QuoVadis Root CA 3 G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 @@ -3438,10 +3508,10 @@ u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Security Communication ECC RootCA1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx @@ -3454,10 +3524,10 @@ ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu 9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Security Communication RootCA2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX @@ -3477,10 +3547,10 @@ okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // AAA Certificate Services - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj @@ -3504,10 +3574,10 @@ Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // COMODO Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV @@ -3531,10 +3601,10 @@ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // COMODO ECC Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT @@ -3549,10 +3619,10 @@ BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // COMODO RSA Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV @@ -3585,10 +3655,10 @@ S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB NVOFBkpdn627G190 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Sectigo Public Email Protection Root E46 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICMTCCAbegAwIBAgIQbvXTp0GOoFlApzBr0kBlVjAKBggqhkjOPQQDAzBaMQsw CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTEwLwYDVQQDEyhT ZWN0aWdvIFB1YmxpYyBFbWFpbCBQcm90ZWN0aW9uIFJvb3QgRTQ2MB4XDTIxMDMy @@ -3601,10 +3671,10 @@ HQYDVR0OBBYEFC1OjKfCI7JXqQZrPmsrifPDXkfOMA4GA1UdDwEB/wQEAwIBhjAP BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCSnRpZY0VYjhsW5H16 bDZIMB8rcueQMzT9JKLGBoxvOzJXWvj+xkkSU5rZELKZUXICMAUlKjMh/JPmIqLM cFUoNVaiB8QhhCMaTEyZUJmSFMtK3Fb79dOPaiz1cTr4izsDng== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Sectigo Public Email Protection Root R46 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFgDCCA2igAwIBAgIQHUSeuQ2DkXSu3fLriLemozANBgkqhkiG9w0BAQwFADBa MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTEwLwYDVQQD EyhTZWN0aWdvIFB1YmxpYyBFbWFpbCBQcm90ZWN0aW9uIFJvb3QgUjQ2MB4XDTIx @@ -3635,10 +3705,10 @@ IS+0AlmzLdBykLoLFHR4S8/BX1VyjlQrE876WAzTuyzZqZFh+PjxtnvevKnMkgTM S2tfc4C2Ie1QT9d2h27O39K3vWKhfVhiaEVStj/eEtvtBGmedoiqAW3ahsdgG8NS rDfsUHGAciohRQpTRzwZ643SWQTeJbDrHzVvYH3Xtca7CyeN4E1U5c8dJgFuOzXI IBKJg/DS7Vg7NJ27MfUy/THzVho= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Sectigo Public Server Authentication Root E46 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN @@ -3651,10 +3721,10 @@ WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q 4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Sectigo Public Server Authentication Root R46 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw @@ -3685,10 +3755,10 @@ dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp 0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // USERTrust ECC Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT @@ -3703,10 +3773,10 @@ A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // USERTrust RSA Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV @@ -3739,10 +3809,10 @@ qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com Client ECC Root CA 2022 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICQDCCAcagAwIBAgIQdvhIHq7wPHAf4D8lVAGD1TAKBggqhkjOPQQDAzBRMQsw CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQDDB9T U0wuY29tIENsaWVudCBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzAzMloX @@ -3756,10 +3826,10 @@ U81SGi9dYKDDXfuyHBwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUC ME0HES0R+7kmwyHdcuEX/MHPFOpJznGHjtZT3BHNXVSKr9kt9IxR6rxmR+J/lYNg ZQIxAIwhTE+75bBQ35BiSebMkdv4P11xkQiOT5LJf6Zc6hN+7W3E6MMqb1wR4aXz alqaTQ== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com Client RSA Root CA 2022 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFjzCCA3egAwIBAgIQdq/uiJMVRbZQU5uAnKTfmjANBgkqhkiG9w0BAQsFADBR MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQD DB9TU0wuY29tIENsaWVudCBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzEw @@ -3790,10 +3860,10 @@ miZPPiDPT0PzEIx/EGF6NsqqC33Mn0dEWa6llcaZU+MHaz1JELAY/10OhUMUS+dr OdmsupJ13UPKugGVrRqBKzrw48UvDBhNEMauwO3+BVJ/GQXLqa81CAw4IuT+VuVT Pr/k1rPZCMM91TMygSTFqeFlEbgyMzBxGEkdGkXGmhSKWDkobvPLUblJJmR4A8eR EYOpuZA0tm+qBZ6FKFeZvn8nBkliTaH8CeErRglMFJtWj0U= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com EV Root Certification Authority ECC - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp @@ -3808,10 +3878,10 @@ MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX 5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com EV Root Certification Authority RSA R2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy @@ -3844,10 +3914,10 @@ QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com Root Certification Authority ECC - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 @@ -3862,10 +3932,10 @@ EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com Root Certification Authority RSA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp @@ -3898,10 +3968,10 @@ K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com TLS ECC Root CA 2022 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 @@ -3914,10 +3984,10 @@ GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp 15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SSL.com TLS RSA Root CA 2022 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX @@ -3948,10 +4018,10 @@ AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU 98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SwissSign Gold CA - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF @@ -3983,45 +4053,10 @@ hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE-----'`)) - - // SwissSign Silver CA - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu -IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow -RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY -U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv -Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br -YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF -nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH -6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt -eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ -c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ -MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH -HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf -jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 -5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB -rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c -wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB -AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp -WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 -xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ -2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ -IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 -aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X -em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR -dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ -OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ -hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy -tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TWCA CYBER Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 @@ -4052,10 +4087,10 @@ Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TWCA Global Root CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 @@ -4085,10 +4120,10 @@ nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy KwbQBM0= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TWCA Global Root CA G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFlTCCA32gAwIBAgIQQAE0jMIAAAAAAAAAAZdY9DANBgkqhkiG9w0BAQwFADBU MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 IENBMR8wHQYDVQQDExZUV0NBIEdsb2JhbCBSb290IENBIEcyMB4XDTIyMTEyMjA2 @@ -4119,10 +4154,10 @@ UamsVsAhTqMUdAU6vOO/bT1OP16lpG0pv4RRdVOOhhr1UXAqDRxOQOH9o+OlK2eQ ksdsroW/OpsXFcqcKpPUTTkNvCAIo42IbAkNjK5EIU3JcezYJtcXni0RGDyjIn24 J1S/aMg7QsyPXk7n3MLF+mpED41WiHrfiYRsoLM+PfFlAAmI6irrQM6zXawyF67B m+nQwfVJlN2nznxaB+uuIJwXMJJpk3Lzmltxm/5q33owaY6zLtsPLN0= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TWCA Root Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz @@ -4142,10 +4177,10 @@ XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Telia Root CA v2 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 @@ -4176,10 +4211,10 @@ Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA rBPuUBQemMc= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // TeliaSonera Root CA v1 - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD @@ -4208,10 +4243,10 @@ vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Secure Global CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx @@ -4232,10 +4267,10 @@ H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // SecureTrust CA - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz @@ -4256,10 +4291,10 @@ NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Trustwave Global Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 @@ -4292,10 +4327,10 @@ VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK yeC2nOnOcXHebD8WpHk= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Trustwave Global ECC P256 Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 @@ -4309,10 +4344,10 @@ FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // Trustwave Global ECC P384 Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 @@ -4328,10 +4363,10 @@ A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu Sw== ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) // XRamp Global Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`'-----BEGIN CERTIFICATE----- + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY @@ -4355,5 +4390,5 @@ qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE-----'`)) +-----END CERTIFICATE-----`)) } From fd5e5d13dcbfe804ec94d1c93f9c779def6fdd4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 14 Feb 2025 13:43:07 +0800 Subject: [PATCH 49/62] Update dependencies --- .golangci.yml | 2 +- common/tls/acme.go | 2 +- experimental/v2rayapi/stats.pb.go | 246 +++++++------------------ experimental/v2rayapi/stats_grpc.pb.go | 29 ++- go.mod | 38 ++-- go.sum | 96 ++++++---- transport/v2raygrpc/client.go | 2 +- transport/v2raygrpc/conn.go | 1 + transport/v2raygrpc/custom_name.go | 2 +- transport/v2raygrpc/stream.pb.go | 45 ++--- transport/v2raygrpc/stream_grpc.pb.go | 81 +++----- 11 files changed, 215 insertions(+), 329 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index cdd53eca..1117e075 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -21,7 +21,7 @@ linters-settings: - -SA1003 run: - go: "1.23" + go: "1.24" build-tags: - with_gvisor - with_quic diff --git a/common/tls/acme.go b/common/tls/acme.go index 08b24ed2..3f251473 100644 --- a/common/tls/acme.go +++ b/common/tls/acme.go @@ -16,7 +16,7 @@ import ( "github.com/caddyserver/certmagic" "github.com/libdns/alidns" "github.com/libdns/cloudflare" - "github.com/mholt/acmez/acme" + "github.com/mholt/acmez/v3/acme" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) diff --git a/experimental/v2rayapi/stats.pb.go b/experimental/v2rayapi/stats.pb.go index 45cde824..19a5f619 100644 --- a/experimental/v2rayapi/stats.pb.go +++ b/experimental/v2rayapi/stats.pb.go @@ -3,6 +3,7 @@ package v2rayapi import ( reflect "reflect" sync "sync" + unsafe "unsafe" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" @@ -16,23 +17,20 @@ const ( ) type GetStatsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Name of the stat counter. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Whether or not to reset the counter to fetching its value. - Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"` + Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetStatsRequest) Reset() { *x = GetStatsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetStatsRequest) String() string { @@ -43,7 +41,7 @@ func (*GetStatsRequest) ProtoMessage() {} func (x *GetStatsRequest) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -73,21 +71,18 @@ func (x *GetStatsRequest) GetReset_() bool { } type Stat struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Stat) Reset() { *x = Stat{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Stat) String() string { @@ -98,7 +93,7 @@ func (*Stat) ProtoMessage() {} func (x *Stat) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -128,20 +123,17 @@ func (x *Stat) GetValue() int64 { } type GetStatsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Stat *Stat `protobuf:"bytes,1,opt,name=stat,proto3" json:"stat,omitempty"` unknownFields protoimpl.UnknownFields - - Stat *Stat `protobuf:"bytes,1,opt,name=stat,proto3" json:"stat,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetStatsResponse) Reset() { *x = GetStatsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetStatsResponse) String() string { @@ -152,7 +144,7 @@ func (*GetStatsResponse) ProtoMessage() {} func (x *GetStatsResponse) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -175,24 +167,21 @@ func (x *GetStatsResponse) GetStat() *Stat { } type QueryStatsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Deprecated, use Patterns instead - Pattern string `protobuf:"bytes,1,opt,name=pattern,proto3" json:"pattern,omitempty"` - Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"` - Patterns []string `protobuf:"bytes,3,rep,name=patterns,proto3" json:"patterns,omitempty"` - Regexp bool `protobuf:"varint,4,opt,name=regexp,proto3" json:"regexp,omitempty"` + Pattern string `protobuf:"bytes,1,opt,name=pattern,proto3" json:"pattern,omitempty"` + Reset_ bool `protobuf:"varint,2,opt,name=reset,proto3" json:"reset,omitempty"` + Patterns []string `protobuf:"bytes,3,rep,name=patterns,proto3" json:"patterns,omitempty"` + Regexp bool `protobuf:"varint,4,opt,name=regexp,proto3" json:"regexp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *QueryStatsRequest) Reset() { *x = QueryStatsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QueryStatsRequest) String() string { @@ -203,7 +192,7 @@ func (*QueryStatsRequest) ProtoMessage() {} func (x *QueryStatsRequest) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -247,20 +236,17 @@ func (x *QueryStatsRequest) GetRegexp() bool { } type QueryStatsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Stat []*Stat `protobuf:"bytes,1,rep,name=stat,proto3" json:"stat,omitempty"` unknownFields protoimpl.UnknownFields - - Stat []*Stat `protobuf:"bytes,1,rep,name=stat,proto3" json:"stat,omitempty"` + sizeCache protoimpl.SizeCache } func (x *QueryStatsResponse) Reset() { *x = QueryStatsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QueryStatsResponse) String() string { @@ -271,7 +257,7 @@ func (*QueryStatsResponse) ProtoMessage() {} func (x *QueryStatsResponse) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -294,18 +280,16 @@ func (x *QueryStatsResponse) GetStat() []*Stat { } type SysStatsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SysStatsRequest) Reset() { *x = SysStatsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SysStatsRequest) String() string { @@ -316,7 +300,7 @@ func (*SysStatsRequest) ProtoMessage() {} func (x *SysStatsRequest) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -332,29 +316,26 @@ func (*SysStatsRequest) Descriptor() ([]byte, []int) { } type SysStatsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NumGoroutine uint32 `protobuf:"varint,1,opt,name=NumGoroutine,proto3" json:"NumGoroutine,omitempty"` + NumGC uint32 `protobuf:"varint,2,opt,name=NumGC,proto3" json:"NumGC,omitempty"` + Alloc uint64 `protobuf:"varint,3,opt,name=Alloc,proto3" json:"Alloc,omitempty"` + TotalAlloc uint64 `protobuf:"varint,4,opt,name=TotalAlloc,proto3" json:"TotalAlloc,omitempty"` + Sys uint64 `protobuf:"varint,5,opt,name=Sys,proto3" json:"Sys,omitempty"` + Mallocs uint64 `protobuf:"varint,6,opt,name=Mallocs,proto3" json:"Mallocs,omitempty"` + Frees uint64 `protobuf:"varint,7,opt,name=Frees,proto3" json:"Frees,omitempty"` + LiveObjects uint64 `protobuf:"varint,8,opt,name=LiveObjects,proto3" json:"LiveObjects,omitempty"` + PauseTotalNs uint64 `protobuf:"varint,9,opt,name=PauseTotalNs,proto3" json:"PauseTotalNs,omitempty"` + Uptime uint32 `protobuf:"varint,10,opt,name=Uptime,proto3" json:"Uptime,omitempty"` unknownFields protoimpl.UnknownFields - - NumGoroutine uint32 `protobuf:"varint,1,opt,name=NumGoroutine,proto3" json:"NumGoroutine,omitempty"` - NumGC uint32 `protobuf:"varint,2,opt,name=NumGC,proto3" json:"NumGC,omitempty"` - Alloc uint64 `protobuf:"varint,3,opt,name=Alloc,proto3" json:"Alloc,omitempty"` - TotalAlloc uint64 `protobuf:"varint,4,opt,name=TotalAlloc,proto3" json:"TotalAlloc,omitempty"` - Sys uint64 `protobuf:"varint,5,opt,name=Sys,proto3" json:"Sys,omitempty"` - Mallocs uint64 `protobuf:"varint,6,opt,name=Mallocs,proto3" json:"Mallocs,omitempty"` - Frees uint64 `protobuf:"varint,7,opt,name=Frees,proto3" json:"Frees,omitempty"` - LiveObjects uint64 `protobuf:"varint,8,opt,name=LiveObjects,proto3" json:"LiveObjects,omitempty"` - PauseTotalNs uint64 `protobuf:"varint,9,opt,name=PauseTotalNs,proto3" json:"PauseTotalNs,omitempty"` - Uptime uint32 `protobuf:"varint,10,opt,name=Uptime,proto3" json:"Uptime,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SysStatsResponse) Reset() { *x = SysStatsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_experimental_v2rayapi_stats_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_experimental_v2rayapi_stats_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SysStatsResponse) String() string { @@ -365,7 +346,7 @@ func (*SysStatsResponse) ProtoMessage() {} func (x *SysStatsResponse) ProtoReflect() protoreflect.Message { mi := &file_experimental_v2rayapi_stats_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -452,7 +433,7 @@ func (x *SysStatsResponse) GetUptime() uint32 { var File_experimental_v2rayapi_stats_proto protoreflect.FileDescriptor -var file_experimental_v2rayapi_stats_proto_rawDesc = []byte{ +var file_experimental_v2rayapi_stats_proto_rawDesc = string([]byte{ 0x0a, 0x21, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, @@ -523,23 +504,23 @@ var file_experimental_v2rayapi_stats_proto_rawDesc = []byte{ 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x78, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_experimental_v2rayapi_stats_proto_rawDescOnce sync.Once - file_experimental_v2rayapi_stats_proto_rawDescData = file_experimental_v2rayapi_stats_proto_rawDesc + file_experimental_v2rayapi_stats_proto_rawDescData []byte ) func file_experimental_v2rayapi_stats_proto_rawDescGZIP() []byte { file_experimental_v2rayapi_stats_proto_rawDescOnce.Do(func() { - file_experimental_v2rayapi_stats_proto_rawDescData = protoimpl.X.CompressGZIP(file_experimental_v2rayapi_stats_proto_rawDescData) + file_experimental_v2rayapi_stats_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_experimental_v2rayapi_stats_proto_rawDesc), len(file_experimental_v2rayapi_stats_proto_rawDesc))) }) return file_experimental_v2rayapi_stats_proto_rawDescData } var ( file_experimental_v2rayapi_stats_proto_msgTypes = make([]protoimpl.MessageInfo, 7) - file_experimental_v2rayapi_stats_proto_goTypes = []interface{}{ + file_experimental_v2rayapi_stats_proto_goTypes = []any{ (*GetStatsRequest)(nil), // 0: experimental.v2rayapi.GetStatsRequest (*Stat)(nil), // 1: experimental.v2rayapi.Stat (*GetStatsResponse)(nil), // 2: experimental.v2rayapi.GetStatsResponse @@ -571,97 +552,11 @@ func file_experimental_v2rayapi_stats_proto_init() { if File_experimental_v2rayapi_stats_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_experimental_v2rayapi_stats_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetStatsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_experimental_v2rayapi_stats_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Stat); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_experimental_v2rayapi_stats_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetStatsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_experimental_v2rayapi_stats_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryStatsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_experimental_v2rayapi_stats_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryStatsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_experimental_v2rayapi_stats_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SysStatsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_experimental_v2rayapi_stats_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SysStatsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_experimental_v2rayapi_stats_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_experimental_v2rayapi_stats_proto_rawDesc), len(file_experimental_v2rayapi_stats_proto_rawDesc)), NumEnums: 0, NumMessages: 7, NumExtensions: 0, @@ -672,7 +567,6 @@ func file_experimental_v2rayapi_stats_proto_init() { MessageInfos: file_experimental_v2rayapi_stats_proto_msgTypes, }.Build() File_experimental_v2rayapi_stats_proto = out.File - file_experimental_v2rayapi_stats_proto_rawDesc = nil file_experimental_v2rayapi_stats_proto_goTypes = nil file_experimental_v2rayapi_stats_proto_depIdxs = nil } diff --git a/experimental/v2rayapi/stats_grpc.pb.go b/experimental/v2rayapi/stats_grpc.pb.go index ee950287..3788f520 100644 --- a/experimental/v2rayapi/stats_grpc.pb.go +++ b/experimental/v2rayapi/stats_grpc.pb.go @@ -10,8 +10,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( StatsService_GetStats_FullMethodName = "/experimental.v2rayapi.StatsService/GetStats" @@ -37,8 +37,9 @@ func NewStatsServiceClient(cc grpc.ClientConnInterface) StatsServiceClient { } func (c *statsServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetStatsResponse) - err := c.cc.Invoke(ctx, StatsService_GetStats_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, StatsService_GetStats_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -46,8 +47,9 @@ func (c *statsServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, } func (c *statsServiceClient) QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(QueryStatsResponse) - err := c.cc.Invoke(ctx, StatsService_QueryStats_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, StatsService_QueryStats_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -55,8 +57,9 @@ func (c *statsServiceClient) QueryStats(ctx context.Context, in *QueryStatsReque } func (c *statsServiceClient) GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SysStatsResponse) - err := c.cc.Invoke(ctx, StatsService_GetSysStats_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, StatsService_GetSysStats_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -65,7 +68,7 @@ func (c *statsServiceClient) GetSysStats(ctx context.Context, in *SysStatsReques // StatsServiceServer is the server API for StatsService service. // All implementations must embed UnimplementedStatsServiceServer -// for forward compatibility +// for forward compatibility. type StatsServiceServer interface { GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) @@ -73,7 +76,11 @@ type StatsServiceServer interface { mustEmbedUnimplementedStatsServiceServer() } -// UnimplementedStatsServiceServer must be embedded to have forward compatible implementations. +// UnimplementedStatsServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. type UnimplementedStatsServiceServer struct{} func (UnimplementedStatsServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) { @@ -88,6 +95,7 @@ func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsReq return nil, status.Errorf(codes.Unimplemented, "method GetSysStats not implemented") } func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {} +func (UnimplementedStatsServiceServer) testEmbeddedByValue() {} // UnsafeStatsServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to StatsServiceServer will @@ -97,6 +105,13 @@ type UnsafeStatsServiceServer interface { } func RegisterStatsServiceServer(s grpc.ServiceRegistrar, srv StatsServiceServer) { + // If the following call pancis, it indicates UnimplementedStatsServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&StatsService_ServiceDesc, srv) } diff --git a/go.mod b/go.mod index c0bdbfcf..1a2a50fa 100644 --- a/go.mod +++ b/go.mod @@ -5,20 +5,20 @@ go 1.23.1 toolchain go1.24.0 require ( - github.com/caddyserver/certmagic v0.20.0 - github.com/cloudflare/circl v1.3.7 + github.com/caddyserver/certmagic v0.21.7 + github.com/cloudflare/circl v1.6.0 github.com/cretz/bine v0.2.0 github.com/go-chi/chi/v5 v5.2.1 github.com/go-chi/render v1.0.3 - github.com/gofrs/uuid/v5 v5.3.0 + github.com/gofrs/uuid/v5 v5.3.1 github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 github.com/libdns/alidns v1.0.3 github.com/libdns/cloudflare v0.1.1 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 - github.com/mholt/acmez v1.2.0 + github.com/mholt/acmez/v3 v3.0.1 github.com/miekg/dns v1.1.63 - github.com/oschwald/maxminddb-golang v1.12.0 + github.com/oschwald/maxminddb-golang v1.13.1 github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 @@ -45,14 +45,14 @@ require ( github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/crypto v0.32.0 + golang.org/x/crypto v0.33.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - golang.org/x/mod v0.20.0 - golang.org/x/net v0.34.0 + golang.org/x/mod v0.23.0 + golang.org/x/net v0.35.0 golang.org/x/sys v0.30.0 - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 - google.golang.org/grpc v1.63.2 - google.golang.org/protobuf v1.33.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 + google.golang.org/grpc v1.70.0 + google.golang.org/protobuf v1.36.5 howett.net/plist v1.0.1 ) @@ -65,6 +65,7 @@ require ( github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/coder/websocket v1.8.12 // indirect github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect @@ -97,13 +98,13 @@ require ( github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect github.com/jsimonetti/rtnetlink v1.4.0 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/libdns/libdns v0.2.2 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/sdnotify v1.0.0 // indirect - github.com/mdlayher/socket v0.5.0 // indirect + github.com/mdlayher/socket v0.5.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/onsi/ginkgo/v2 v2.17.2 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect @@ -127,17 +128,18 @@ require ( github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap/exp v0.3.0 // indirect go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/term v0.29.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.24.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 7424346f..9d6f0a1b 100644 --- a/go.sum +++ b/go.sum @@ -10,14 +10,16 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= -github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= +github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg= +github.com/caddyserver/certmagic v0.21.7/go.mod h1:LCPG3WLxcnjVKl/xpjzM0gqh0knrKKKiO5WVttX2eEI= +github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= +github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= +github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= @@ -48,8 +50,10 @@ github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= @@ -60,10 +64,12 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= -github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= -github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gofrs/uuid/v5 v5.3.1 h1:aPx49MwJbekCzOyhZDjJVb0hx3A0KLjlbLx6p2gY0p0= +github.com/gofrs/uuid/v5 v5.3.1/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -101,9 +107,8 @@ github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUF github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ= @@ -121,12 +126,12 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= -github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= -github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= -github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= -github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= +github.com/mholt/acmez/v3 v3.0.1 h1:4PcjKjaySlgXK857aTfDuRbmnM5gb3Ruz3tvoSJAUp8= +github.com/mholt/acmez/v3 v3.0.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= @@ -137,8 +142,8 @@ github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= -github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= -github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= +github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= +github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= @@ -240,36 +245,48 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= +go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -278,18 +295,17 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -300,16 +316,16 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= diff --git a/transport/v2raygrpc/client.go b/transport/v2raygrpc/client.go index af922b45..e649aa8f 100644 --- a/transport/v2raygrpc/client.go +++ b/transport/v2raygrpc/client.go @@ -62,6 +62,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt dialOptions = append(dialOptions, grpc.WithContextDialer(func(ctx context.Context, server string) (net.Conn, error) { return dialer.DialContext(ctx, N.NetworkTCP, M.ParseSocksaddr(server)) })) + //nolint:staticcheck dialOptions = append(dialOptions, grpc.WithReturnConnectionError()) return &Client{ ctx: ctx, @@ -84,7 +85,6 @@ func (c *Client) connect() (*grpc.ClientConn, error) { return conn, nil } //nolint:staticcheck - //goland:noinspection GoDeprecation conn, err := grpc.DialContext(c.ctx, c.serverAddr, c.dialOptions...) if err != nil { return nil, err diff --git a/transport/v2raygrpc/conn.go b/transport/v2raygrpc/conn.go index 0a0a627f..c29da4f9 100644 --- a/transport/v2raygrpc/conn.go +++ b/transport/v2raygrpc/conn.go @@ -18,6 +18,7 @@ type GRPCConn struct { } func NewGRPCConn(service GunService) *GRPCConn { + //nolint:staticcheck if client, isClient := service.(GunService_TunClient); isClient { service = &clientConnWrapper{client} } diff --git a/transport/v2raygrpc/custom_name.go b/transport/v2raygrpc/custom_name.go index 1fe7d8cc..ce970dc6 100644 --- a/transport/v2raygrpc/custom_name.go +++ b/transport/v2raygrpc/custom_name.go @@ -34,7 +34,7 @@ func (c *gunServiceClient) TunCustomName(ctx context.Context, name string, opts if err != nil { return nil, err } - x := &gunServiceTunClient{stream} + x := &grpc.GenericClientStream[Hunk, Hunk]{ClientStream: stream} return x, nil } diff --git a/transport/v2raygrpc/stream.pb.go b/transport/v2raygrpc/stream.pb.go index 26c091e1..fc2688b5 100644 --- a/transport/v2raygrpc/stream.pb.go +++ b/transport/v2raygrpc/stream.pb.go @@ -3,6 +3,7 @@ package v2raygrpc import ( reflect "reflect" sync "sync" + unsafe "unsafe" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" @@ -16,20 +17,17 @@ const ( ) type Hunk struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Hunk) Reset() { *x = Hunk{} - if protoimpl.UnsafeEnabled { - mi := &file_transport_v2raygrpc_stream_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_transport_v2raygrpc_stream_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Hunk) String() string { @@ -40,7 +38,7 @@ func (*Hunk) ProtoMessage() {} func (x *Hunk) ProtoReflect() protoreflect.Message { mi := &file_transport_v2raygrpc_stream_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -64,7 +62,7 @@ func (x *Hunk) GetData() []byte { var File_transport_v2raygrpc_stream_proto protoreflect.FileDescriptor -var file_transport_v2raygrpc_stream_proto_rawDesc = []byte{ +var file_transport_v2raygrpc_stream_proto_rawDesc = string([]byte{ 0x0a, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x76, 0x32, @@ -79,23 +77,23 @@ var file_transport_v2raygrpc_stream_proto_rawDesc = []byte{ 0x2f, 0x73, 0x61, 0x67, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x78, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_transport_v2raygrpc_stream_proto_rawDescOnce sync.Once - file_transport_v2raygrpc_stream_proto_rawDescData = file_transport_v2raygrpc_stream_proto_rawDesc + file_transport_v2raygrpc_stream_proto_rawDescData []byte ) func file_transport_v2raygrpc_stream_proto_rawDescGZIP() []byte { file_transport_v2raygrpc_stream_proto_rawDescOnce.Do(func() { - file_transport_v2raygrpc_stream_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_v2raygrpc_stream_proto_rawDescData) + file_transport_v2raygrpc_stream_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_v2raygrpc_stream_proto_rawDesc), len(file_transport_v2raygrpc_stream_proto_rawDesc))) }) return file_transport_v2raygrpc_stream_proto_rawDescData } var ( file_transport_v2raygrpc_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 1) - file_transport_v2raygrpc_stream_proto_goTypes = []interface{}{ + file_transport_v2raygrpc_stream_proto_goTypes = []any{ (*Hunk)(nil), // 0: transport.v2raygrpc.Hunk } ) @@ -115,25 +113,11 @@ func file_transport_v2raygrpc_stream_proto_init() { if File_transport_v2raygrpc_stream_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_transport_v2raygrpc_stream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hunk); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_transport_v2raygrpc_stream_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_v2raygrpc_stream_proto_rawDesc), len(file_transport_v2raygrpc_stream_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -144,7 +128,6 @@ func file_transport_v2raygrpc_stream_proto_init() { MessageInfos: file_transport_v2raygrpc_stream_proto_msgTypes, }.Build() File_transport_v2raygrpc_stream_proto = out.File - file_transport_v2raygrpc_stream_proto_rawDesc = nil file_transport_v2raygrpc_stream_proto_goTypes = nil file_transport_v2raygrpc_stream_proto_depIdxs = nil } diff --git a/transport/v2raygrpc/stream_grpc.pb.go b/transport/v2raygrpc/stream_grpc.pb.go index ea634849..d602ec45 100644 --- a/transport/v2raygrpc/stream_grpc.pb.go +++ b/transport/v2raygrpc/stream_grpc.pb.go @@ -10,8 +10,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( GunService_Tun_FullMethodName = "/transport.v2raygrpc.GunService/Tun" @@ -21,7 +21,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type GunServiceClient interface { - Tun(ctx context.Context, opts ...grpc.CallOption) (GunService_TunClient, error) + Tun(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Hunk, Hunk], error) } type gunServiceClient struct { @@ -32,52 +32,39 @@ func NewGunServiceClient(cc grpc.ClientConnInterface) GunServiceClient { return &gunServiceClient{cc} } -func (c *gunServiceClient) Tun(ctx context.Context, opts ...grpc.CallOption) (GunService_TunClient, error) { - stream, err := c.cc.NewStream(ctx, &GunService_ServiceDesc.Streams[0], GunService_Tun_FullMethodName, opts...) +func (c *gunServiceClient) Tun(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Hunk, Hunk], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &GunService_ServiceDesc.Streams[0], GunService_Tun_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &gunServiceTunClient{stream} + x := &grpc.GenericClientStream[Hunk, Hunk]{ClientStream: stream} return x, nil } -type GunService_TunClient interface { - Send(*Hunk) error - Recv() (*Hunk, error) - grpc.ClientStream -} - -type gunServiceTunClient struct { - grpc.ClientStream -} - -func (x *gunServiceTunClient) Send(m *Hunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *gunServiceTunClient) Recv() (*Hunk, error) { - m := new(Hunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type GunService_TunClient = grpc.BidiStreamingClient[Hunk, Hunk] // GunServiceServer is the server API for GunService service. // All implementations must embed UnimplementedGunServiceServer -// for forward compatibility +// for forward compatibility. type GunServiceServer interface { - Tun(GunService_TunServer) error + Tun(grpc.BidiStreamingServer[Hunk, Hunk]) error mustEmbedUnimplementedGunServiceServer() } -// UnimplementedGunServiceServer must be embedded to have forward compatible implementations. +// UnimplementedGunServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. type UnimplementedGunServiceServer struct{} -func (UnimplementedGunServiceServer) Tun(GunService_TunServer) error { +func (UnimplementedGunServiceServer) Tun(grpc.BidiStreamingServer[Hunk, Hunk]) error { return status.Errorf(codes.Unimplemented, "method Tun not implemented") } func (UnimplementedGunServiceServer) mustEmbedUnimplementedGunServiceServer() {} +func (UnimplementedGunServiceServer) testEmbeddedByValue() {} // UnsafeGunServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to GunServiceServer will @@ -87,34 +74,22 @@ type UnsafeGunServiceServer interface { } func RegisterGunServiceServer(s grpc.ServiceRegistrar, srv GunServiceServer) { + // If the following call pancis, it indicates UnimplementedGunServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&GunService_ServiceDesc, srv) } func _GunService_Tun_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(GunServiceServer).Tun(&gunServiceTunServer{stream}) + return srv.(GunServiceServer).Tun(&grpc.GenericServerStream[Hunk, Hunk]{ServerStream: stream}) } -type GunService_TunServer interface { - Send(*Hunk) error - Recv() (*Hunk, error) - grpc.ServerStream -} - -type gunServiceTunServer struct { - grpc.ServerStream -} - -func (x *gunServiceTunServer) Send(m *Hunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *gunServiceTunServer) Recv() (*Hunk, error) { - m := new(Hunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type GunService_TunServer = grpc.BidiStreamingServer[Hunk, Hunk] // GunService_ServiceDesc is the grpc.ServiceDesc for GunService service. // It's only intended for direct use with grpc.RegisterService, From 0c85f49c3b9e1956d532efc3aa8bed10fc2ae6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 16 Feb 2025 11:49:24 +0800 Subject: [PATCH 50/62] Add back port hopping to hysteria 1 --- docs/configuration/outbound/hysteria.md | 29 ++++++++++++++++++++++ docs/configuration/outbound/hysteria.zh.md | 29 ++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +-- option/hysteria.go | 26 +++++++++++-------- protocol/hysteria/outbound.go | 24 ++++++++++-------- 6 files changed, 89 insertions(+), 25 deletions(-) diff --git a/docs/configuration/outbound/hysteria.md b/docs/configuration/outbound/hysteria.md index 90190e05..b326e06d 100644 --- a/docs/configuration/outbound/hysteria.md +++ b/docs/configuration/outbound/hysteria.md @@ -1,3 +1,12 @@ +--- +icon: material/new-box +--- + +!!! quote "Changes in sing-box 1.12.0" + + :material-plus: [server_ports](#server_ports) + :material-plus: [hop_interval](#hop_interval) + ### Structure ```json @@ -7,6 +16,10 @@ "server": "127.0.0.1", "server_port": 1080, + "server_ports": [ + "2080:3000" + ], + "hop_interval": "", "up": "100 Mbps", "up_mbps": 100, "down": "100 Mbps", @@ -38,6 +51,22 @@ The server address. The server port. +#### server_ports + +!!! question "Since sing-box 1.12.0" + +Server port range list. + +Conflicts with `server_port`. + +#### hop_interval + +!!! question "Since sing-box 1.12.0" + +Port hopping interval. + +`30s` is used by default. + #### up, down ==Required== diff --git a/docs/configuration/outbound/hysteria.zh.md b/docs/configuration/outbound/hysteria.zh.md index c6ee2313..4f4c00bb 100644 --- a/docs/configuration/outbound/hysteria.zh.md +++ b/docs/configuration/outbound/hysteria.zh.md @@ -1,3 +1,12 @@ +--- +icon: material/new-box +--- + +!!! quote "sing-box 1.12.0 中的更改" + + :material-plus: [server_ports](#server_ports) + :material-plus: [hop_interval](#hop_interval) + ### 结构 ```json @@ -7,6 +16,10 @@ "server": "127.0.0.1", "server_port": 1080, + "server_ports": [ + "2080:3000" + ], + "hop_interval": "", "up": "100 Mbps", "up_mbps": 100, "down": "100 Mbps", @@ -38,6 +51,22 @@ 服务器端口。 +#### server_ports + +!!! question "自 sing-box 1.12.0 起" + +服务器端口范围列表。 + +与 `server_port` 冲突。 + +#### hop_interval + +!!! question "自 sing-box 1.12.0 起" + +端口跳跃间隔。 + +默认使用 `30s`。 + #### up, down ==必填== diff --git a/go.mod b/go.mod index 1a2a50fa..e69417fc 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff github.com/sagernet/sing-mux v0.3.1 - github.com/sagernet/sing-quic v0.4.0 + github.com/sagernet/sing-quic v0.4.1-beta.1 github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowtls v0.2.0 diff --git a/go.sum b/go.sum index 9d6f0a1b..ebbe57cd 100644 --- a/go.sum +++ b/go.sum @@ -186,8 +186,8 @@ github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff h1:5UGghwx8cI14qFa github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78= -github.com/sagernet/sing-quic v0.4.0 h1:E4geazHk/UrJTXMlT+CBCKmn8V86RhtNeczWtfeoEFc= -github.com/sagernet/sing-quic v0.4.0/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys= +github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s= +github.com/sagernet/sing-quic v0.4.1-beta.1/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= diff --git a/option/hysteria.go b/option/hysteria.go index beb3685e..c3dc78ef 100644 --- a/option/hysteria.go +++ b/option/hysteria.go @@ -1,5 +1,7 @@ package option +import "github.com/sagernet/sing/common/json/badoption" + type HysteriaInboundOptions struct { ListenOptions Up string `json:"up,omitempty"` @@ -24,16 +26,18 @@ type HysteriaUser struct { type HysteriaOutboundOptions struct { DialerOptions ServerOptions - Up string `json:"up,omitempty"` - UpMbps int `json:"up_mbps,omitempty"` - Down string `json:"down,omitempty"` - DownMbps int `json:"down_mbps,omitempty"` - Obfs string `json:"obfs,omitempty"` - Auth []byte `json:"auth,omitempty"` - AuthString string `json:"auth_str,omitempty"` - ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` - ReceiveWindow uint64 `json:"recv_window,omitempty"` - DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` - Network NetworkList `json:"network,omitempty"` + ServerPorts badoption.Listable[string] `json:"server_ports,omitempty"` + HopInterval badoption.Duration `json:"hop_interval,omitempty"` + Up string `json:"up,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + Down string `json:"down,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` + Obfs string `json:"obfs,omitempty"` + Auth []byte `json:"auth,omitempty"` + AuthString string `json:"auth_str,omitempty"` + ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` + ReceiveWindow uint64 `json:"recv_window,omitempty"` + DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` + Network NetworkList `json:"network,omitempty"` OutboundTLSOptionsContainer } diff --git a/protocol/hysteria/outbound.go b/protocol/hysteria/outbound.go index 7746df13..d3035c71 100644 --- a/protocol/hysteria/outbound.go +++ b/protocol/hysteria/outbound.go @@ -4,6 +4,7 @@ import ( "context" "net" "os" + "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter/outbound" @@ -76,17 +77,18 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps } client, err := hysteria.NewClient(hysteria.ClientOptions{ - Context: ctx, - Dialer: outboundDialer, - Logger: logger, - ServerAddress: options.ServerOptions.Build(), - SendBPS: sendBps, - ReceiveBPS: receiveBps, - XPlusPassword: options.Obfs, - Password: password, - TLSConfig: tlsConfig, - UDPDisabled: !common.Contains(networkList, N.NetworkUDP), - + Context: ctx, + Dialer: outboundDialer, + Logger: logger, + ServerAddress: options.ServerOptions.Build(), + ServerPorts: options.ServerPorts, + HopInterval: time.Duration(options.HopInterval), + SendBPS: sendBps, + ReceiveBPS: receiveBps, + XPlusPassword: options.Obfs, + Password: password, + TLSConfig: tlsConfig, + UDPDisabled: !common.Contains(networkList, N.NetworkUDP), ConnReceiveWindow: options.ReceiveWindowConn, StreamReceiveWindow: options.ReceiveWindow, DisableMTUDiscovery: options.DisableMTUDiscovery, From 0e48fc4498c0795ff81ae9e15bd5dfdd26672b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 18 Feb 2025 19:13:25 +0800 Subject: [PATCH 51/62] Fix toolchain version --- .goreleaser.yaml | 2 ++ Makefile | 7 +++++-- go.mod | 2 -- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 4d7fd502..15e2fa3a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -24,6 +24,7 @@ builds: - with_tailscale env: - CGO_ENABLED=0 + - GOTOOLCHAIN=local targets: - linux_386 - linux_amd64_v1 @@ -62,6 +63,7 @@ builds: <<: *template env: - CGO_ENABLED=1 + - GOTOOLCHAIN=local overrides: - goos: android goarch: arm diff --git a/Makefile b/Makefile index ab399a29..1a084b01 100644 --- a/Makefile +++ b/Makefile @@ -18,14 +18,17 @@ PREFIX ?= $(shell go env GOPATH) .PHONY: test release docs build build: + export GOTOOLCHAIN=local && \ go build $(MAIN_PARAMS) $(MAIN) ci_build_go120: - go build $(PARAMS) $(MAIN) + export GOTOOLCHAIN=local && \ + go build $(PARAMS) $(MAIN) && \ go build $(PARAMS) -tags "$(TAGS_GO120)" $(MAIN) ci_build: - go build $(PARAMS) $(MAIN) + export GOTOOLCHAIN=local && \ + go build $(PARAMS) $(MAIN) && \ go build $(MAIN_PARAMS) $(MAIN) generate_completions: diff --git a/go.mod b/go.mod index e69417fc..18c25300 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/sagernet/sing-box go 1.23.1 -toolchain go1.24.0 - require ( github.com/caddyserver/certmagic v0.21.7 github.com/cloudflare/circl v1.6.0 From b2073bc39a9a4b72e7189789a018981fb0e7473e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 20 Feb 2025 15:13:14 +0800 Subject: [PATCH 52/62] Improve resolve action --- docs/configuration/dns/rule_action.md | 4 +-- docs/configuration/dns/rule_action.zh.md | 4 +-- docs/configuration/route/rule_action.md | 36 ++++++++++++++++--- docs/configuration/route/rule_action.zh.md | 31 +++++++++++++++-- option/rule_action.go | 7 ++-- route/route.go | 7 ++-- route/rule/rule_action.go | 40 ++++++++++++++++------ 7 files changed, 103 insertions(+), 26 deletions(-) diff --git a/docs/configuration/dns/rule_action.md b/docs/configuration/dns/rule_action.md index c3f8c2cb..33c283fa 100644 --- a/docs/configuration/dns/rule_action.md +++ b/docs/configuration/dns/rule_action.md @@ -16,7 +16,7 @@ icon: material/new-box "server": "", "strategy": "", "disable_cache": false, - "rewrite_ttl": 0, + "rewrite_ttl": null, "client_subnet": null } ``` @@ -49,7 +49,7 @@ Append a `edns0-subnet` OPT extra record with the specified IP prefix to every q If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically. -Will overrides `dns.client_subnet` and `servers.[].client_subnet`. +Will overrides `dns.client_subnet`. ### route-options diff --git a/docs/configuration/dns/rule_action.zh.md b/docs/configuration/dns/rule_action.zh.md index 427f8a8d..03843ec5 100644 --- a/docs/configuration/dns/rule_action.zh.md +++ b/docs/configuration/dns/rule_action.zh.md @@ -17,7 +17,7 @@ icon: material/new-box "strategy": "", "disable_cache": false, - "rewrite_ttl": 0, + "rewrite_ttl": null, "client_subnet": null } ``` @@ -50,7 +50,7 @@ icon: material/new-box 如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。 -将覆盖 `dns.client_subnet` 与 `servers.[].client_subnet`。 +将覆盖 `dns.client_subnet`. ### route-options diff --git a/docs/configuration/route/rule_action.md b/docs/configuration/route/rule_action.md index 567b9eb6..0f04b165 100644 --- a/docs/configuration/route/rule_action.md +++ b/docs/configuration/route/rule_action.md @@ -5,7 +5,10 @@ icon: material/new-box !!! quote "Changes in sing-box 1.12.0" :material-plus: [tls_fragment](#tls_fragment) - :material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay) + :material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay) + :material-plus: [resolve.disable_cache](#disable_cache) + :material-plus: [resolve.rewrite_ttl](#rewrite_ttl) + :material-plus: [resolve.client_subnet](#client_subnet) ## Final actions @@ -210,19 +213,44 @@ Timeout for sniffing. ```json { "action": "resolve", + "server": "", "strategy": "", - "server": "" + "disable_cache": false, + "rewrite_ttl": null, + "client_subnet": null } ``` `resolve` resolve request destination from domain to IP addresses. +#### server + +Specifies DNS server tag to use instead of selecting through DNS routing. + #### strategy DNS resolution strategy, available values are: `prefer_ipv4`, `prefer_ipv6`, `ipv4_only`, `ipv6_only`. `dns.strategy` will be used by default. -#### server +#### disable_cache -Specifies DNS server tag to use instead of selecting through DNS routing. +!!! question "Since sing-box 1.12.0" + +Disable cache and save cache in this query. + +#### rewrite_ttl + +!!! question "Since sing-box 1.12.0" + +Rewrite TTL in DNS responses. + +#### client_subnet + +!!! question "Since sing-box 1.12.0" + +Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default. + +If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically. + +Will overrides `dns.client_subnet`. diff --git a/docs/configuration/route/rule_action.zh.md b/docs/configuration/route/rule_action.zh.md index a8eca8a2..f0c91610 100644 --- a/docs/configuration/route/rule_action.zh.md +++ b/docs/configuration/route/rule_action.zh.md @@ -206,19 +206,44 @@ UDP 连接超时时间。 ```json { "action": "resolve", + "server": "", "strategy": "", - "server": "" + "disable_cache": false, + "rewrite_ttl": null, + "client_subnet": null } ``` `resolve` 将请求的目标从域名解析为 IP 地址。 +#### server + +指定要使用的 DNS 服务器的标签,而不是通过 DNS 路由进行选择。 + #### strategy DNS 解析策略,可用值有:`prefer_ipv4`、`prefer_ipv6`、`ipv4_only`、`ipv6_only`。 默认使用 `dns.strategy`。 -#### server +#### disable_cache -指定要使用的 DNS 服务器的标签,而不是通过 DNS 路由进行选择。 +!!! question "自 sing-box 1.12.0 起" + +在此查询中禁用缓存。 + +#### rewrite_ttl + +!!! question "自 sing-box 1.12.0 起" + +重写 DNS 回应中的 TTL。 + +#### client_subnet + +!!! question "自 sing-box 1.12.0 起" + +默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。 + +如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。 + +将覆盖 `dns.client_subnet`. diff --git a/option/rule_action.go b/option/rule_action.go index f07d7298..00d3ae7a 100644 --- a/option/rule_action.go +++ b/option/rule_action.go @@ -288,6 +288,9 @@ type RouteActionSniff struct { } type RouteActionResolve struct { - Strategy DomainStrategy `json:"strategy,omitempty"` - Server string `json:"server,omitempty"` + Server string `json:"server,omitempty"` + Strategy DomainStrategy `json:"strategy,omitempty"` + DisableCache bool `json:"disable_cache,omitempty"` + RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"` + ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"` } diff --git a/route/route.go b/route/route.go index 2b15d650..73a14c33 100644 --- a/route/route.go +++ b/route/route.go @@ -666,8 +666,11 @@ func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundCon } } addresses, err := r.dns.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, adapter.DNSQueryOptions{ - Transport: transport, - Strategy: action.Strategy, + Transport: transport, + Strategy: action.Strategy, + DisableCache: action.DisableCache, + RewriteTTL: action.RewriteTTL, + ClientSubnet: action.ClientSubnet, }) if err != nil { return err diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index 96515dad..fe5ce39c 100644 --- a/route/rule/rule_action.go +++ b/route/rule/rule_action.go @@ -88,8 +88,11 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti return sniffAction, sniffAction.build() case C.RuleActionTypeResolve: return &RuleActionResolve{ - Strategy: C.DomainStrategy(action.ResolveOptions.Strategy), - Server: action.ResolveOptions.Server, + Server: action.ResolveOptions.Server, + Strategy: C.DomainStrategy(action.ResolveOptions.Strategy), + DisableCache: action.ResolveOptions.DisableCache, + RewriteTTL: action.ResolveOptions.RewriteTTL, + ClientSubnet: action.ResolveOptions.ClientSubnet.Build(netip.Prefix{}), }, nil default: panic(F.ToString("unknown rule action: ", action.Action)) @@ -376,8 +379,11 @@ func (r *RuleActionSniff) String() string { } type RuleActionResolve struct { - Strategy C.DomainStrategy - Server string + Server string + Strategy C.DomainStrategy + DisableCache bool + RewriteTTL *uint32 + ClientSubnet netip.Prefix } func (r *RuleActionResolve) Type() string { @@ -385,13 +391,25 @@ func (r *RuleActionResolve) Type() string { } func (r *RuleActionResolve) String() string { - if r.Strategy == C.DomainStrategyAsIS && r.Server == "" { - return F.ToString("resolve") - } else if r.Strategy != C.DomainStrategyAsIS && r.Server == "" { - return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ")") - } else if r.Strategy == C.DomainStrategyAsIS && r.Server != "" { - return F.ToString("resolve(", r.Server, ")") + var options []string + if r.Server != "" { + options = append(options, r.Server) + } + if r.Strategy != C.DomainStrategyAsIS { + options = append(options, F.ToString(option.DomainStrategy(r.Strategy))) + } + if r.DisableCache { + options = append(options, "disable_cache") + } + if r.RewriteTTL != nil { + options = append(options, F.ToString("rewrite_ttl=", *r.RewriteTTL)) + } + if r.ClientSubnet.IsValid() { + options = append(options, F.ToString("client_subnet=", r.ClientSubnet)) + } + if len(options) == 0 { + return "resolve" } else { - return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ",", r.Server, ")") + return F.ToString("resolve(", strings.Join(options, ","), ")") } } From cb390ccd4599c85c054bb387b4d1cec83356571c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 20 Feb 2025 16:40:53 +0800 Subject: [PATCH 53/62] Get darwin local DNS server from libresolv --- dns/transport/local/local.go | 1 + dns/transport/local/resolv_darwin_cgo.go | 53 ++++++++++++++++++++++++ dns/transport/local/resolv_default.go | 23 ++++++++++ dns/transport/local/resolv_unix.go | 30 +++----------- dns/transport_manager.go | 4 +- protocol/tun/hook.go | 3 ++ protocol/tun/inbound.go | 3 ++ 7 files changed, 90 insertions(+), 27 deletions(-) create mode 100644 dns/transport/local/resolv_darwin_cgo.go create mode 100644 dns/transport/local/resolv_default.go create mode 100644 protocol/tun/hook.go diff --git a/dns/transport/local/local.go b/dns/transport/local/local.go index e5e8aef9..7f02c608 100644 --- a/dns/transport/local/local.go +++ b/dns/transport/local/local.go @@ -27,6 +27,7 @@ var _ adapter.DNSTransport = (*Transport)(nil) type Transport struct { dns.TransportAdapter + ctx context.Context hosts *hosts.File dialer N.Dialer } diff --git a/dns/transport/local/resolv_darwin_cgo.go b/dns/transport/local/resolv_darwin_cgo.go new file mode 100644 index 00000000..dfcb8a8a --- /dev/null +++ b/dns/transport/local/resolv_darwin_cgo.go @@ -0,0 +1,53 @@ +//go:build darwin && cgo + +package local + +/* +#include +#include +#include +#include +*/ +import "C" + +import ( + "time" + + E "github.com/sagernet/sing/common/exceptions" + + "github.com/miekg/dns" +) + +func dnsReadConfig(_ string) *dnsConfig { + if C.res_init() != 0 { + return &dnsConfig{ + servers: defaultNS, + search: dnsDefaultSearch(), + ndots: 1, + timeout: 5 * time.Second, + attempts: 2, + err: E.New("libresolv initialization failed"), + } + } + conf := &dnsConfig{ + ndots: 1, + timeout: 5 * time.Second, + attempts: int(C._res.retry), + } + for i := 0; i < int(C._res.nscount); i++ { + ns := C._res.nsaddr_list[i] + addr := C.inet_ntoa(ns.sin_addr) + if addr == nil { + continue + } + conf.servers = append(conf.servers, C.GoString(addr)) + } + for i := 0; ; i++ { + search := C._res.dnsrch[i] + if search == nil { + break + } + conf.search = append(conf.search, dns.Fqdn(C.GoString(search))) + } + return conf +} diff --git a/dns/transport/local/resolv_default.go b/dns/transport/local/resolv_default.go new file mode 100644 index 00000000..0a7d8810 --- /dev/null +++ b/dns/transport/local/resolv_default.go @@ -0,0 +1,23 @@ +package local + +import ( + "os" + "strings" + _ "unsafe" + + "github.com/miekg/dns" +) + +//go:linkname defaultNS net.defaultNS +var defaultNS []string + +func dnsDefaultSearch() []string { + hn, err := os.Hostname() + if err != nil { + return nil + } + if i := strings.IndexRune(hn, '.'); i >= 0 && i < len(hn)-1 { + return []string{dns.Fqdn(hn[i+1:])} + } + return nil +} diff --git a/dns/transport/local/resolv_unix.go b/dns/transport/local/resolv_unix.go index 6594ae41..c3953145 100644 --- a/dns/transport/local/resolv_unix.go +++ b/dns/transport/local/resolv_unix.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build !windows && !(darwin && cgo) package local @@ -9,7 +9,8 @@ import ( "os" "strings" "time" - _ "unsafe" + + "github.com/miekg/dns" ) func dnsReadConfig(name string) *dnsConfig { @@ -69,13 +70,13 @@ func dnsReadConfig(name string) *dnsConfig { } case "domain": if len(f) > 1 { - conf.search = []string{ensureRooted(f[1])} + conf.search = []string{dns.Fqdn(f[1])} } case "search": conf.search = make([]string, 0, len(f)-1) for i := 1; i < len(f); i++ { - name := ensureRooted(f[i]) + name := dns.Fqdn(f[i]) if name == "." { continue } @@ -137,27 +138,6 @@ func dnsReadConfig(name string) *dnsConfig { return conf } -//go:linkname defaultNS net.defaultNS -var defaultNS []string - -func dnsDefaultSearch() []string { - hn, err := os.Hostname() - if err != nil { - return nil - } - if i := strings.IndexRune(hn, '.'); i >= 0 && i < len(hn)-1 { - return []string{ensureRooted(hn[i+1:])} - } - return nil -} - -func ensureRooted(s string) string { - if len(s) > 0 && s[len(s)-1] == '.' { - return s - } - return s + "." -} - const big = 0xFFFFFF func dtoi(s string) (n int, i int, ok bool) { diff --git a/dns/transport_manager.go b/dns/transport_manager.go index 4497923b..8666a1b9 100644 --- a/dns/transport_manager.go +++ b/dns/transport_manager.go @@ -56,12 +56,12 @@ func (m *TransportManager) Start(stage adapter.StartStage) error { } m.started = true m.stage = stage - outbounds := m.transports + transports := m.transports m.access.Unlock() if stage == adapter.StartStateStart { return m.startTransports(m.transports) } else { - for _, outbound := range outbounds { + for _, outbound := range transports { err := adapter.LegacyStart(outbound, stage) if err != nil { return E.Cause(err, stage, " dns/", outbound.Type(), "[", outbound.Tag(), "]") diff --git a/protocol/tun/hook.go b/protocol/tun/hook.go new file mode 100644 index 00000000..1afa643f --- /dev/null +++ b/protocol/tun/hook.go @@ -0,0 +1,3 @@ +package tun + +var HookBeforeCreatePlatformInterface func() diff --git a/protocol/tun/inbound.go b/protocol/tun/inbound.go index 00cc0561..088780ed 100644 --- a/protocol/tun/inbound.go +++ b/protocol/tun/inbound.go @@ -361,6 +361,9 @@ func (t *Inbound) Start(stage adapter.StartStage) error { if t.platformInterface != nil { tunInterface, err = t.platformInterface.OpenTun(&tunOptions, t.platformOptions) } else { + if HookBeforeCreatePlatformInterface != nil { + HookBeforeCreatePlatformInterface() + } tunInterface, err = tun.New(tunOptions) } monitor.Finish() From 462807a43bae740a456f3bb81732d525ba92b869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 20 Feb 2025 17:18:47 +0800 Subject: [PATCH 54/62] Add fallback local DNS server for iOS --- common/tls/ech_client.go | 2 +- dns/client.go | 78 +++++++++- dns/rcode.go | 38 ++--- dns/router.go | 4 +- dns/transport/local/local.go | 4 - dns/transport/local/local_fallback.go | 201 ++++++++++++++++++++++++++ dns/transport/local/resolv_windows.go | 3 - dns/transport/predefined.go | 2 +- experimental/libbox/dns.go | 2 +- protocol/dns/handle.go | 2 +- protocol/tailscale/dns_transport.go | 2 +- 11 files changed, 293 insertions(+), 45 deletions(-) create mode 100644 dns/transport/local/local_fallback.go diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index 80219350..9c3744b4 100644 --- a/common/tls/ech_client.go +++ b/common/tls/ech_client.go @@ -221,7 +221,7 @@ func fetchECHClientConfig(ctx context.Context) func(_ context.Context, serverNam return nil, err } if response.Rcode != mDNS.RcodeSuccess { - return nil, dns.RCodeError(response.Rcode) + return nil, dns.RcodeError(response.Rcode) } for _, rr := range response.Answer { switch resource := rr.(type) { diff --git a/dns/client.go b/dns/client.go index 79b6fce5..d44883b5 100644 --- a/dns/client.go +++ b/dns/client.go @@ -17,7 +17,7 @@ import ( "github.com/sagernet/sing/contrab/freelru" "github.com/sagernet/sing/contrab/maphash" - "github.com/miekg/dns" + dns "github.com/miekg/dns" ) var ( @@ -484,7 +484,7 @@ func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransp func MessageToAddresses(response *dns.Msg) ([]netip.Addr, error) { if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError { - return nil, RCodeError(response.Rcode) + return nil, RcodeError(response.Rcode) } addresses := make([]netip.Addr, 0, len(response.Answer)) for _, rawAnswer := range response.Answer { @@ -508,10 +508,10 @@ func wrapError(err error) error { switch dnsErr := err.(type) { case *net.DNSError: if dnsErr.IsNotFound { - return RCodeNameError + return RcodeNameError } case *net.AddrError: - return RCodeNameError + return RcodeNameError } return err } @@ -561,3 +561,73 @@ func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, tim } return &response } + +func FixedResponseCNAME(id uint16, question dns.Question, record string, timeToLive uint32) *dns.Msg { + response := dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: id, + Rcode: dns.RcodeSuccess, + Response: true, + }, + Question: []dns.Question{question}, + Answer: []dns.RR{ + &dns.CNAME{ + Hdr: dns.RR_Header{ + Name: question.Name, + Rrtype: dns.TypeCNAME, + Class: dns.ClassINET, + Ttl: timeToLive, + }, + Target: record, + }, + }, + } + return &response +} + +func FixedResponseTXT(id uint16, question dns.Question, records []string, timeToLive uint32) *dns.Msg { + response := dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: id, + Rcode: dns.RcodeSuccess, + Response: true, + }, + Question: []dns.Question{question}, + Answer: []dns.RR{ + &dns.TXT{ + Hdr: dns.RR_Header{ + Name: question.Name, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: timeToLive, + }, + Txt: records, + }, + }, + } + return &response +} + +func FixedResponseMX(id uint16, question dns.Question, records []*net.MX, timeToLive uint32) *dns.Msg { + response := dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: id, + Rcode: dns.RcodeSuccess, + Response: true, + }, + Question: []dns.Question{question}, + } + for _, record := range records { + response.Answer = append(response.Answer, &dns.MX{ + Hdr: dns.RR_Header{ + Name: question.Name, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: timeToLive, + }, + Preference: record.Pref, + Mx: record.Host, + }) + } + return &response +} diff --git a/dns/rcode.go b/dns/rcode.go index 5b7e52cc..08545474 100644 --- a/dns/rcode.go +++ b/dns/rcode.go @@ -1,33 +1,17 @@ package dns -import F "github.com/sagernet/sing/common/format" - -const ( - RCodeSuccess RCodeError = 0 // NoError - RCodeFormatError RCodeError = 1 // FormErr - RCodeServerFailure RCodeError = 2 // ServFail - RCodeNameError RCodeError = 3 // NXDomain - RCodeNotImplemented RCodeError = 4 // NotImp - RCodeRefused RCodeError = 5 // Refused +import ( + mDNS "github.com/miekg/dns" ) -type RCodeError uint16 +const ( + RcodeFormatError RcodeError = mDNS.RcodeFormatError + RcodeNameError RcodeError = mDNS.RcodeNameError + RcodeRefused RcodeError = mDNS.RcodeRefused +) -func (e RCodeError) Error() string { - switch e { - case RCodeSuccess: - return "success" - case RCodeFormatError: - return "format error" - case RCodeServerFailure: - return "server failure" - case RCodeNameError: - return "name error" - case RCodeNotImplemented: - return "not implemented" - case RCodeRefused: - return "refused" - default: - return F.ToString("unknown error: ", uint16(e)) - } +type RcodeError int + +func (e RcodeError) Error() string { + return mDNS.RcodeToString[int(e)] } diff --git a/dns/router.go b/dns/router.go index 4102128e..5db5429a 100644 --- a/dns/router.go +++ b/dns/router.go @@ -329,13 +329,13 @@ func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQ } } else if len(responseAddrs) == 0 { r.logger.ErrorContext(ctx, "lookup failed for ", domain, ": empty result") - err = RCodeNameError + err = RcodeNameError } } responseAddrs, cached = r.client.LookupCache(domain, options.Strategy) if cached { if len(responseAddrs) == 0 { - return nil, RCodeNameError + return nil, RcodeNameError } return responseAddrs, nil } diff --git a/dns/transport/local/local.go b/dns/transport/local/local.go index 7f02c608..e4236275 100644 --- a/dns/transport/local/local.go +++ b/dns/transport/local/local.go @@ -19,10 +19,6 @@ import ( mDNS "github.com/miekg/dns" ) -func RegisterTransport(registry *dns.TransportRegistry) { - dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewTransport) -} - var _ adapter.DNSTransport = (*Transport)(nil) type Transport struct { diff --git a/dns/transport/local/local_fallback.go b/dns/transport/local/local_fallback.go new file mode 100644 index 00000000..0a7cd9f0 --- /dev/null +++ b/dns/transport/local/local_fallback.go @@ -0,0 +1,201 @@ +package local + +import ( + "context" + "errors" + "net" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/experimental/libbox/platform" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/service" + + mDNS "github.com/miekg/dns" +) + +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewFallbackTransport) +} + +type FallbackTransport struct { + adapter.DNSTransport + ctx context.Context + fallback bool + resolver net.Resolver +} + +func NewFallbackTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) { + transport, err := NewTransport(ctx, logger, tag, options) + if err != nil { + return nil, err + } + return &FallbackTransport{ + DNSTransport: transport, + ctx: ctx, + }, nil +} + +func (f *FallbackTransport) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + platformInterface := service.FromContext[platform.Interface](f.ctx) + if platformInterface == nil { + return nil + } + inboundManager := service.FromContext[adapter.InboundManager](f.ctx) + for _, inbound := range inboundManager.Inbounds() { + if inbound.Type() == C.TypeTun { + // platform tun hijacks DNS, so we can only use cgo resolver here + f.fallback = true + break + } + } + return nil +} + +func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + if f.fallback { + return f.DNSTransport.Exchange(ctx, message) + } + question := message.Question[0] + domain := dns.FqdnToDomain(question.Name) + if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA { + var network string + if question.Qtype == mDNS.TypeA { + network = "ip4" + } else { + network = "ip6" + } + addresses, err := f.resolver.LookupNetIP(ctx, network, domain) + if err != nil { + var dnsError *net.DNSError + if errors.As(err, &dnsError) && dnsError.IsNotFound { + return nil, dns.RcodeRefused + } + return nil, err + } + return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil + } else if question.Qtype == mDNS.TypeNS { + records, err := f.resolver.LookupNS(ctx, domain) + if err != nil { + var dnsError *net.DNSError + if errors.As(err, &dnsError) && dnsError.IsNotFound { + return nil, dns.RcodeRefused + } + return nil, err + } + response := &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeSuccess, + Response: true, + }, + Question: []mDNS.Question{question}, + } + for _, record := range records { + response.Answer = append(response.Answer, &mDNS.NS{ + Hdr: mDNS.RR_Header{ + Name: question.Name, + Rrtype: mDNS.TypeNS, + Class: mDNS.ClassINET, + Ttl: C.DefaultDNSTTL, + }, + Ns: record.Host, + }) + } + return response, nil + } else if question.Qtype == mDNS.TypeCNAME { + cname, err := f.resolver.LookupCNAME(ctx, domain) + if err != nil { + var dnsError *net.DNSError + if errors.As(err, &dnsError) && dnsError.IsNotFound { + return nil, dns.RcodeRefused + } + return nil, err + } + return &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeSuccess, + Response: true, + }, + Question: []mDNS.Question{question}, + Answer: []mDNS.RR{ + &mDNS.CNAME{ + Hdr: mDNS.RR_Header{ + Name: question.Name, + Rrtype: mDNS.TypeCNAME, + Class: mDNS.ClassINET, + Ttl: C.DefaultDNSTTL, + }, + Target: cname, + }, + }, + }, nil + } else if question.Qtype == mDNS.TypeTXT { + records, err := f.resolver.LookupTXT(ctx, domain) + if err != nil { + var dnsError *net.DNSError + if errors.As(err, &dnsError) && dnsError.IsNotFound { + return nil, dns.RcodeRefused + } + return nil, err + } + return &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeSuccess, + Response: true, + }, + Question: []mDNS.Question{question}, + Answer: []mDNS.RR{ + &mDNS.TXT{ + Hdr: mDNS.RR_Header{ + Name: question.Name, + Rrtype: mDNS.TypeCNAME, + Class: mDNS.ClassINET, + Ttl: C.DefaultDNSTTL, + }, + Txt: records, + }, + }, + }, nil + } else if question.Qtype == mDNS.TypeMX { + records, err := f.resolver.LookupMX(ctx, domain) + if err != nil { + var dnsError *net.DNSError + if errors.As(err, &dnsError) && dnsError.IsNotFound { + return nil, dns.RcodeRefused + } + return nil, err + } + response := &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeSuccess, + Response: true, + }, + Question: []mDNS.Question{question}, + } + for _, record := range records { + response.Answer = append(response.Answer, &mDNS.MX{ + Hdr: mDNS.RR_Header{ + Name: question.Name, + Rrtype: mDNS.TypeA, + Class: mDNS.ClassINET, + Ttl: C.DefaultDNSTTL, + }, + Preference: record.Pref, + Mx: record.Host, + }) + } + return response, nil + } else { + return nil, E.New("only A, AAAA, NS, CNAME, TXT, MX queries are supported on current platform when using TUN, please switch to a fixed DNS server.") + } +} diff --git a/dns/transport/local/resolv_windows.go b/dns/transport/local/resolv_windows.go index 577e7a12..f6b81090 100644 --- a/dns/transport/local/resolv_windows.go +++ b/dns/transport/local/resolv_windows.go @@ -69,9 +69,6 @@ func dnsReadConfig(_ string) *dnsConfig { return conf } -//go:linkname defaultNS net.defaultNS -var defaultNS []string - func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { var b []byte l := uint32(15000) // recommended initial size diff --git a/dns/transport/predefined.go b/dns/transport/predefined.go index 3f112886..dbb78e5c 100644 --- a/dns/transport/predefined.go +++ b/dns/transport/predefined.go @@ -79,5 +79,5 @@ func (t *PredefinedTransport) Exchange(ctx context.Context, message *mDNS.Msg) ( } } } - return nil, dns.RCodeNameError + return nil, dns.RcodeNameError } diff --git a/experimental/libbox/dns.go b/experimental/libbox/dns.go index a7ccd2a2..7e143442 100644 --- a/experimental/libbox/dns.go +++ b/experimental/libbox/dns.go @@ -134,7 +134,7 @@ func (c *ExchangeContext) RawSuccess(result []byte) { } func (c *ExchangeContext) ErrorCode(code int32) { - c.error = dns.RCodeError(code) + c.error = dns.RcodeError(code) } func (c *ExchangeContext) ErrnoCode(code int32) { diff --git a/protocol/dns/handle.go b/protocol/dns/handle.go index c4ad79d9..765e5051 100644 --- a/protocol/dns/handle.go +++ b/protocol/dns/handle.go @@ -26,7 +26,7 @@ func HandleStreamDNSRequest(ctx context.Context, router adapter.DNSRouter, conn return err } if queryLength == 0 { - return dns.RCodeFormatError + return dns.RcodeFormatError } buffer := buf.NewSize(int(queryLength)) defer buffer.Release() diff --git a/protocol/tailscale/dns_transport.go b/protocol/tailscale/dns_transport.go index 0c83c698..3447b6b2 100644 --- a/protocol/tailscale/dns_transport.go +++ b/protocol/tailscale/dns_transport.go @@ -287,7 +287,7 @@ func (t *DNSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M return nil, E.New("missing default resolvers") } } - return nil, dns.RCodeNameError + return nil, dns.RcodeNameError } type DNSDialer struct { From 84c14614b7828e4ca94fb24d8a684aeb9c2cb578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 22 Feb 2025 08:00:59 +0800 Subject: [PATCH 55/62] Migrate to stdlib ECH support --- .golangci.yml | 1 - .goreleaser.fury.yaml | 1 - .goreleaser.yaml | 1 - Dockerfile | 2 +- Makefile | 5 +- cmd/internal/build_libbox/main.go | 2 +- cmd/sing-box/cmd_generate_ech.go | 5 +- common/badtls/read_wait_ech.go | 31 --- common/tls/client.go | 7 +- common/tls/ech.go | 174 +++++++++++++ common/tls/ech_client.go | 244 ----------------- common/tls/ech_keygen.go | 19 +- common/tls/ech_quic.go | 55 ---- common/tls/ech_server.go | 278 -------------------- common/tls/ech_stub.go | 18 +- common/tls/mkcert.go | 6 +- common/tls/server.go | 7 +- common/tls/std_client.go | 3 + common/tls/std_server.go | 50 ++-- docs/configuration/shared/tls.md | 38 ++- docs/configuration/shared/tls.zh.md | 56 ++-- docs/deprecated.md | 11 + docs/deprecated.zh.md | 9 + docs/installation/build-from-source.md | 36 ++- docs/installation/build-from-source.zh.md | 6 +- experimental/deprecated/constants.go | 10 + experimental/deprecated/stderr.go | 16 +- go.mod | 1 - go.sum | 2 - option/tls.go | 26 +- test/box_test.go | 2 +- test/ech_test.go | 6 +- test/go.mod | 133 ++++++---- test/go.sum | 303 ++++++++++++++-------- 34 files changed, 667 insertions(+), 897 deletions(-) delete mode 100644 common/badtls/read_wait_ech.go create mode 100644 common/tls/ech.go delete mode 100644 common/tls/ech_client.go delete mode 100644 common/tls/ech_quic.go delete mode 100644 common/tls/ech_server.go diff --git a/.golangci.yml b/.golangci.yml index 1117e075..d212ebb2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -27,7 +27,6 @@ run: - with_quic - with_dhcp - with_wireguard - - with_ech - with_utls - with_reality_server - with_acme diff --git a/.goreleaser.fury.yaml b/.goreleaser.fury.yaml index de5c5db9..beef42ec 100644 --- a/.goreleaser.fury.yaml +++ b/.goreleaser.fury.yaml @@ -14,7 +14,6 @@ builds: - with_quic - with_dhcp - with_wireguard - - with_ech - with_utls - with_reality_server - with_acme diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 15e2fa3a..ddb69247 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -16,7 +16,6 @@ builds: - with_quic - with_dhcp - with_wireguard - - with_ech - with_utls - with_reality_server - with_acme diff --git a/Dockerfile b/Dockerfile index 6c3cfd39..c9b32b8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN set -ex \ && export COMMIT=$(git rev-parse --short HEAD) \ && export VERSION=$(go run ./cmd/internal/read_tag) \ && go build -v -trimpath -tags \ - "with_gvisor,with_quic,with_dhcp,with_wireguard,with_ech,with_utls,with_reality_server,with_acme,with_clash_api" \ + "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_reality_server,with_acme,with_clash_api" \ -o /go/bin/sing-box \ -ldflags "-X \"github.com/sagernet/sing-box/constant.Version=$VERSION\" -s -w -buildid=" \ ./cmd/sing-box diff --git a/Makefile b/Makefile index 1a084b01..68d19eef 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,9 @@ NAME = sing-box COMMIT = $(shell git rev-parse --short HEAD) TAGS_GO120 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api,with_quic,with_utls -TAGS_GO121 = with_ech TAGS_GO123 = with_tailscale -TAGS ?= $(TAGS_GO118),$(TAGS_GO120),$(TAGS_GO121),$(TAGS_GO123) -TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server +TAGS ?= $(TAGS_GO120),$(TAGS_GO123) +TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_utls,with_reality_server GOHOSTOS = $(shell go env GOHOSTOS) GOHOSTARCH = $(shell go env GOHOSTARCH) diff --git a/cmd/internal/build_libbox/main.go b/cmd/internal/build_libbox/main.go index 56cf8688..cad3662b 100644 --- a/cmd/internal/build_libbox/main.go +++ b/cmd/internal/build_libbox/main.go @@ -58,7 +58,7 @@ func init() { sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=") debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag) - sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_ech", "with_utls", "with_clash_api", "with_tailscale") + sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_clash_api", "with_tailscale") iosTags = append(iosTags, "with_dhcp", "with_low_memory", "with_conntrack") debugTags = append(debugTags, "debug") } diff --git a/cmd/sing-box/cmd_generate_ech.go b/cmd/sing-box/cmd_generate_ech.go index 4b5b7be3..7942d588 100644 --- a/cmd/sing-box/cmd_generate_ech.go +++ b/cmd/sing-box/cmd_generate_ech.go @@ -9,8 +9,6 @@ import ( "github.com/spf13/cobra" ) -var pqSignatureSchemesEnabled bool - var commandGenerateECHKeyPair = &cobra.Command{ Use: "ech-keypair ", Short: "Generate TLS ECH key pair", @@ -24,12 +22,11 @@ var commandGenerateECHKeyPair = &cobra.Command{ } func init() { - commandGenerateECHKeyPair.Flags().BoolVar(&pqSignatureSchemesEnabled, "pq-signature-schemes-enabled", false, "Enable PQ signature schemes") commandGenerate.AddCommand(commandGenerateECHKeyPair) } func generateECHKeyPair(serverName string) error { - configPem, keyPem, err := tls.ECHKeygenDefault(serverName, pqSignatureSchemesEnabled) + configPem, keyPem, err := tls.ECHKeygenDefault(serverName) if err != nil { return err } diff --git a/common/badtls/read_wait_ech.go b/common/badtls/read_wait_ech.go deleted file mode 100644 index 6a0d5b5f..00000000 --- a/common/badtls/read_wait_ech.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build go1.21 && !without_badtls && with_ech - -package badtls - -import ( - "net" - _ "unsafe" - - "github.com/sagernet/cloudflare-tls" - "github.com/sagernet/sing/common" -) - -func init() { - tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) { - tlsConn, loaded := common.Cast[*tls.Conn](conn) - if !loaded { - return - } - return true, func() error { - return echReadRecord(tlsConn) - }, func() error { - return echHandlePostHandshakeMessage(tlsConn) - } - }) -} - -//go:linkname echReadRecord github.com/sagernet/cloudflare-tls.(*Conn).readRecord -func echReadRecord(c *tls.Conn) error - -//go:linkname echHandlePostHandshakeMessage github.com/sagernet/cloudflare-tls.(*Conn).handlePostHandshakeMessage -func echHandlePostHandshakeMessage(c *tls.Conn) error diff --git a/common/tls/client.go b/common/tls/client.go index 4d6b0c54..5e05c990 100644 --- a/common/tls/client.go +++ b/common/tls/client.go @@ -29,15 +29,12 @@ func NewClient(ctx context.Context, serverAddress string, options option.Outboun if !options.Enabled { return nil, nil } - if options.ECH != nil && options.ECH.Enabled { - return NewECHClient(ctx, serverAddress, options) - } else if options.Reality != nil && options.Reality.Enabled { + if options.Reality != nil && options.Reality.Enabled { return NewRealityClient(ctx, serverAddress, options) } else if options.UTLS != nil && options.UTLS.Enabled { return NewUTLSClient(ctx, serverAddress, options) - } else { - return NewSTDClient(ctx, serverAddress, options) } + return NewSTDClient(ctx, serverAddress, options) } func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) { diff --git a/common/tls/ech.go b/common/tls/ech.go new file mode 100644 index 00000000..880ca27c --- /dev/null +++ b/common/tls/ech.go @@ -0,0 +1,174 @@ +//go:build go1.24 + +package tls + +import ( + "context" + "crypto/tls" + "encoding/base64" + "encoding/pem" + "net" + "os" + "strings" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/experimental/deprecated" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + aTLS "github.com/sagernet/sing/common/tls" + "github.com/sagernet/sing/service" + + mDNS "github.com/miekg/dns" + "golang.org/x/crypto/cryptobyte" +) + +func parseECHClientConfig(ctx context.Context, options option.OutboundTLSOptions, tlsConfig *tls.Config) (Config, error) { + var echConfig []byte + if len(options.ECH.Config) > 0 { + echConfig = []byte(strings.Join(options.ECH.Config, "\n")) + } else if options.ECH.ConfigPath != "" { + content, err := os.ReadFile(options.ECH.ConfigPath) + if err != nil { + return nil, E.Cause(err, "read ECH config") + } + echConfig = content + } + //nolint:staticcheck + if options.ECH.PQSignatureSchemesEnabled || options.ECH.DynamicRecordSizingDisabled { + deprecated.Report(ctx, deprecated.OptionLegacyECHOptions) + } + if len(echConfig) > 0 { + block, rest := pem.Decode(echConfig) + if block == nil || block.Type != "ECH CONFIGS" || len(rest) > 0 { + return nil, E.New("invalid ECH configs pem") + } + tlsConfig.EncryptedClientHelloConfigList = block.Bytes + return &STDClientConfig{tlsConfig}, nil + } else { + return &STDECHClientConfig{STDClientConfig{tlsConfig}, service.FromContext[adapter.DNSRouter](ctx)}, nil + } +} + +func parseECHServerConfig(ctx context.Context, options option.InboundTLSOptions, tlsConfig *tls.Config, echKeyPath *string) error { + var echKey []byte + if len(options.ECH.Key) > 0 { + echKey = []byte(strings.Join(options.ECH.Key, "\n")) + } else if options.ECH.KeyPath != "" { + content, err := os.ReadFile(options.ECH.KeyPath) + if err != nil { + return E.Cause(err, "read ECH keys") + } + echKey = content + *echKeyPath = options.ECH.KeyPath + } else { + return E.New("missing ECH keys") + } + block, rest := pem.Decode(echKey) + if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 { + return E.New("invalid ECH keys pem") + } + echKeys, err := UnmarshalECHKeys(block.Bytes) + if err != nil { + return E.Cause(err, "parse ECH keys") + } + tlsConfig.EncryptedClientHelloKeys = echKeys + //nolint:staticcheck + if options.ECH.PQSignatureSchemesEnabled || options.ECH.DynamicRecordSizingDisabled { + deprecated.Report(ctx, deprecated.OptionLegacyECHOptions) + } + return nil +} + +func reloadECHKeys(echKeyPath string, tlsConfig *tls.Config) error { + echKey, err := os.ReadFile(echKeyPath) + if err != nil { + return E.Cause(err, "reload ECH keys from ", echKeyPath) + } + block, _ := pem.Decode(echKey) + if block == nil || block.Type != "ECH KEYS" { + return E.New("invalid ECH keys pem") + } + echKeys, err := UnmarshalECHKeys(block.Bytes) + if err != nil { + return E.Cause(err, "parse ECH keys") + } + tlsConfig.EncryptedClientHelloKeys = echKeys + return nil +} + +type STDECHClientConfig struct { + STDClientConfig + dnsRouter adapter.DNSRouter +} + +func (s *STDECHClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (aTLS.Conn, error) { + if len(s.config.EncryptedClientHelloConfigList) == 0 { + message := &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + RecursionDesired: true, + }, + Question: []mDNS.Question{ + { + Name: mDNS.Fqdn(s.config.ServerName), + Qtype: mDNS.TypeHTTPS, + Qclass: mDNS.ClassINET, + }, + }, + } + response, err := s.dnsRouter.Exchange(ctx, message, adapter.DNSQueryOptions{}) + if err != nil { + return nil, E.Cause(err, "fetch ECH config list") + } + if response.Rcode != mDNS.RcodeSuccess { + return nil, E.Cause(dns.RcodeError(response.Rcode), "fetch ECH config list") + } + for _, rr := range response.Answer { + switch resource := rr.(type) { + case *mDNS.HTTPS: + for _, value := range resource.Value { + if value.Key().String() == "ech" { + echConfigList, err := base64.StdEncoding.DecodeString(value.String()) + if err != nil { + return nil, E.Cause(err, "decode ECH config") + } + s.config.EncryptedClientHelloConfigList = echConfigList + } + } + } + } + return nil, E.New("no ECH config found in DNS records") + } + tlsConn, err := s.Client(conn) + if err != nil { + return nil, err + } + err = tlsConn.HandshakeContext(ctx) + if err != nil { + return nil, err + } + return tlsConn, nil +} + +func (s *STDECHClientConfig) Clone() Config { + return &STDECHClientConfig{STDClientConfig{s.config.Clone()}, s.dnsRouter} +} + +func UnmarshalECHKeys(raw []byte) ([]tls.EncryptedClientHelloKey, error) { + var keys []tls.EncryptedClientHelloKey + rawString := cryptobyte.String(raw) + for !rawString.Empty() { + var key tls.EncryptedClientHelloKey + if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.PrivateKey)) { + return nil, E.New("error parsing private key") + } + if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.Config)) { + return nil, E.New("error parsing config") + } + keys = append(keys, key) + } + if len(keys) == 0 { + return nil, E.New("empty ECH keys") + } + return keys, nil +} diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go deleted file mode 100644 index 9c3744b4..00000000 --- a/common/tls/ech_client.go +++ /dev/null @@ -1,244 +0,0 @@ -//go:build with_ech - -package tls - -import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "net" - "net/netip" - "os" - "strings" - - cftls "github.com/sagernet/cloudflare-tls" - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/dns" - "github.com/sagernet/sing-box/option" - E "github.com/sagernet/sing/common/exceptions" - "github.com/sagernet/sing/common/ntp" - "github.com/sagernet/sing/service" - - mDNS "github.com/miekg/dns" -) - -type echClientConfig struct { - config *cftls.Config -} - -func (c *echClientConfig) ServerName() string { - return c.config.ServerName -} - -func (c *echClientConfig) SetServerName(serverName string) { - c.config.ServerName = serverName -} - -func (c *echClientConfig) NextProtos() []string { - return c.config.NextProtos -} - -func (c *echClientConfig) SetNextProtos(nextProto []string) { - c.config.NextProtos = nextProto -} - -func (c *echClientConfig) Config() (*STDConfig, error) { - return nil, E.New("unsupported usage for ECH") -} - -func (c *echClientConfig) Client(conn net.Conn) (Conn, error) { - return &echConnWrapper{cftls.Client(conn, c.config)}, nil -} - -func (c *echClientConfig) Clone() Config { - return &echClientConfig{ - config: c.config.Clone(), - } -} - -type echConnWrapper struct { - *cftls.Conn -} - -func (c *echConnWrapper) ConnectionState() tls.ConnectionState { - state := c.Conn.ConnectionState() - //nolint:staticcheck - return tls.ConnectionState{ - Version: state.Version, - HandshakeComplete: state.HandshakeComplete, - DidResume: state.DidResume, - CipherSuite: state.CipherSuite, - NegotiatedProtocol: state.NegotiatedProtocol, - NegotiatedProtocolIsMutual: state.NegotiatedProtocolIsMutual, - ServerName: state.ServerName, - PeerCertificates: state.PeerCertificates, - VerifiedChains: state.VerifiedChains, - SignedCertificateTimestamps: state.SignedCertificateTimestamps, - OCSPResponse: state.OCSPResponse, - TLSUnique: state.TLSUnique, - } -} - -func (c *echConnWrapper) Upstream() any { - return c.Conn -} - -func NewECHClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) { - var serverName string - if options.ServerName != "" { - serverName = options.ServerName - } else if serverAddress != "" { - if _, err := netip.ParseAddr(serverName); err != nil { - serverName = serverAddress - } - } - if serverName == "" && !options.Insecure { - return nil, E.New("missing server_name or insecure=true") - } - - var tlsConfig cftls.Config - tlsConfig.Time = ntp.TimeFuncFromContext(ctx) - tlsConfig.RootCAs = adapter.RootPoolFromContext(ctx) - if options.DisableSNI { - tlsConfig.ServerName = "127.0.0.1" - } else { - tlsConfig.ServerName = serverName - } - if options.Insecure { - tlsConfig.InsecureSkipVerify = options.Insecure - } else if options.DisableSNI { - tlsConfig.InsecureSkipVerify = true - tlsConfig.VerifyConnection = func(state cftls.ConnectionState) error { - verifyOptions := x509.VerifyOptions{ - DNSName: serverName, - Intermediates: x509.NewCertPool(), - } - for _, cert := range state.PeerCertificates[1:] { - verifyOptions.Intermediates.AddCert(cert) - } - _, err := state.PeerCertificates[0].Verify(verifyOptions) - return err - } - } - if len(options.ALPN) > 0 { - tlsConfig.NextProtos = options.ALPN - } - if options.MinVersion != "" { - minVersion, err := ParseTLSVersion(options.MinVersion) - if err != nil { - return nil, E.Cause(err, "parse min_version") - } - tlsConfig.MinVersion = minVersion - } - if options.MaxVersion != "" { - maxVersion, err := ParseTLSVersion(options.MaxVersion) - if err != nil { - return nil, E.Cause(err, "parse max_version") - } - tlsConfig.MaxVersion = maxVersion - } - if options.CipherSuites != nil { - find: - for _, cipherSuite := range options.CipherSuites { - for _, tlsCipherSuite := range cftls.CipherSuites() { - if cipherSuite == tlsCipherSuite.Name { - tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID) - continue find - } - } - return nil, E.New("unknown cipher_suite: ", cipherSuite) - } - } - var certificate []byte - if len(options.Certificate) > 0 { - certificate = []byte(strings.Join(options.Certificate, "\n")) - } else if options.CertificatePath != "" { - content, err := os.ReadFile(options.CertificatePath) - if err != nil { - return nil, E.Cause(err, "read certificate") - } - certificate = content - } - if len(certificate) > 0 { - certPool := x509.NewCertPool() - if !certPool.AppendCertsFromPEM(certificate) { - return nil, E.New("failed to parse certificate:\n\n", certificate) - } - tlsConfig.RootCAs = certPool - } - - // ECH Config - - tlsConfig.ECHEnabled = true - tlsConfig.PQSignatureSchemesEnabled = options.ECH.PQSignatureSchemesEnabled - tlsConfig.DynamicRecordSizingDisabled = options.ECH.DynamicRecordSizingDisabled - - var echConfig []byte - if len(options.ECH.Config) > 0 { - echConfig = []byte(strings.Join(options.ECH.Config, "\n")) - } else if options.ECH.ConfigPath != "" { - content, err := os.ReadFile(options.ECH.ConfigPath) - if err != nil { - return nil, E.Cause(err, "read ECH config") - } - echConfig = content - } - - if len(echConfig) > 0 { - block, rest := pem.Decode(echConfig) - if block == nil || block.Type != "ECH CONFIGS" || len(rest) > 0 { - return nil, E.New("invalid ECH configs pem") - } - echConfigs, err := cftls.UnmarshalECHConfigs(block.Bytes) - if err != nil { - return nil, E.Cause(err, "parse ECH configs") - } - tlsConfig.ClientECHConfigs = echConfigs - } else { - tlsConfig.GetClientECHConfigs = fetchECHClientConfig(ctx) - } - return &echClientConfig{&tlsConfig}, nil -} - -func fetchECHClientConfig(ctx context.Context) func(_ context.Context, serverName string) ([]cftls.ECHConfig, error) { - return func(_ context.Context, serverName string) ([]cftls.ECHConfig, error) { - message := &mDNS.Msg{ - MsgHdr: mDNS.MsgHdr{ - RecursionDesired: true, - }, - Question: []mDNS.Question{ - { - Name: serverName + ".", - Qtype: mDNS.TypeHTTPS, - Qclass: mDNS.ClassINET, - }, - }, - } - response, err := service.FromContext[adapter.DNSRouter](ctx).Exchange(ctx, message, adapter.DNSQueryOptions{}) - if err != nil { - return nil, err - } - if response.Rcode != mDNS.RcodeSuccess { - return nil, dns.RcodeError(response.Rcode) - } - for _, rr := range response.Answer { - switch resource := rr.(type) { - case *mDNS.HTTPS: - for _, value := range resource.Value { - if value.Key().String() == "ech" { - echConfig, err := base64.StdEncoding.DecodeString(value.String()) - if err != nil { - return nil, E.Cause(err, "decode ECH config") - } - return cftls.UnmarshalECHConfigs(echConfig) - } - } - default: - return nil, E.New("unknown resource record type: ", resource.Header().Rrtype) - } - } - return nil, E.New("no ECH config found") - } -} diff --git a/common/tls/ech_keygen.go b/common/tls/ech_keygen.go index 5053981f..b6c353ac 100644 --- a/common/tls/ech_keygen.go +++ b/common/tls/ech_keygen.go @@ -1,5 +1,3 @@ -//go:build with_ech - package tls import ( @@ -7,14 +5,13 @@ import ( "encoding/binary" "encoding/pem" - cftls "github.com/sagernet/cloudflare-tls" E "github.com/sagernet/sing/common/exceptions" "github.com/cloudflare/circl/hpke" "github.com/cloudflare/circl/kem" ) -func ECHKeygenDefault(serverName string, pqSignatureSchemesEnabled bool) (configPem string, keyPem string, err error) { +func ECHKeygenDefault(serverName string) (configPem string, keyPem string, err error) { cipherSuites := []echCipherSuite{ { kdf: hpke.KDF_HKDF_SHA256, @@ -24,13 +21,9 @@ func ECHKeygenDefault(serverName string, pqSignatureSchemesEnabled bool) (config aead: hpke.AEAD_ChaCha20Poly1305, }, } - keyConfig := []myECHKeyConfig{ {id: 0, kem: hpke.KEM_X25519_HKDF_SHA256}, } - if pqSignatureSchemesEnabled { - keyConfig = append(keyConfig, myECHKeyConfig{id: 1, kem: hpke.KEM_X25519_KYBER768_DRAFT00}) - } keyPairs, err := echKeygen(0xfe0d, serverName, keyConfig, cipherSuites) if err != nil { @@ -59,7 +52,6 @@ func ECHKeygenDefault(serverName string, pqSignatureSchemesEnabled bool) (config type echKeyConfigPair struct { id uint8 - key cftls.EXP_ECHKey rawKey []byte conf myECHKeyConfig rawConf []byte @@ -155,15 +147,6 @@ func echKeygen(version uint16, serverName string, conf []myECHKeyConfig, suite [ sk = append(sk, secBuf...) sk = be.AppendUint16(sk, uint16(len(b))) sk = append(sk, b...) - - cfECHKeys, err := cftls.EXP_UnmarshalECHKeys(sk) - if err != nil { - return nil, E.Cause(err, "bug: can't parse generated ECH server key") - } - if len(cfECHKeys) != 1 { - return nil, E.New("bug: unexpected server key count") - } - pair.key = cfECHKeys[0] pair.rawKey = sk pairs = append(pairs, pair) diff --git a/common/tls/ech_quic.go b/common/tls/ech_quic.go deleted file mode 100644 index 4606090a..00000000 --- a/common/tls/ech_quic.go +++ /dev/null @@ -1,55 +0,0 @@ -//go:build with_quic && with_ech - -package tls - -import ( - "context" - "net" - "net/http" - - "github.com/sagernet/cloudflare-tls" - "github.com/sagernet/quic-go/ech" - "github.com/sagernet/quic-go/http3_ech" - "github.com/sagernet/sing-quic" - M "github.com/sagernet/sing/common/metadata" -) - -var ( - _ qtls.Config = (*echClientConfig)(nil) - _ qtls.ServerConfig = (*echServerConfig)(nil) -) - -func (c *echClientConfig) Dial(ctx context.Context, conn net.PacketConn, addr net.Addr, config *quic.Config) (quic.Connection, error) { - return quic.Dial(ctx, conn, addr, c.config, config) -} - -func (c *echClientConfig) DialEarly(ctx context.Context, conn net.PacketConn, addr net.Addr, config *quic.Config) (quic.EarlyConnection, error) { - return quic.DialEarly(ctx, conn, addr, c.config, config) -} - -func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper { - return &http3.Transport{ - TLSClientConfig: c.config, - QUICConfig: quicConfig, - Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { - quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg) - if err != nil { - return nil, err - } - *quicConnPtr = quicConn - return quicConn, nil - }, - } -} - -func (c *echServerConfig) Listen(conn net.PacketConn, config *quic.Config) (qtls.Listener, error) { - return quic.Listen(conn, c.config, config) -} - -func (c *echServerConfig) ListenEarly(conn net.PacketConn, config *quic.Config) (qtls.EarlyListener, error) { - return quic.ListenEarly(conn, c.config, config) -} - -func (c *echServerConfig) ConfigureHTTP3() { - http3.ConfigureTLSConfig(c.config) -} diff --git a/common/tls/ech_server.go b/common/tls/ech_server.go deleted file mode 100644 index 03f5d876..00000000 --- a/common/tls/ech_server.go +++ /dev/null @@ -1,278 +0,0 @@ -//go:build with_ech - -package tls - -import ( - "context" - "crypto/tls" - "encoding/pem" - "net" - "os" - "strings" - - cftls "github.com/sagernet/cloudflare-tls" - "github.com/sagernet/fswatch" - "github.com/sagernet/sing-box/log" - "github.com/sagernet/sing-box/option" - E "github.com/sagernet/sing/common/exceptions" - "github.com/sagernet/sing/common/ntp" -) - -type echServerConfig struct { - config *cftls.Config - logger log.Logger - certificate []byte - key []byte - certificatePath string - keyPath string - echKeyPath string - watcher *fswatch.Watcher -} - -func (c *echServerConfig) ServerName() string { - return c.config.ServerName -} - -func (c *echServerConfig) SetServerName(serverName string) { - c.config.ServerName = serverName -} - -func (c *echServerConfig) NextProtos() []string { - return c.config.NextProtos -} - -func (c *echServerConfig) SetNextProtos(nextProto []string) { - c.config.NextProtos = nextProto -} - -func (c *echServerConfig) Config() (*STDConfig, error) { - return nil, E.New("unsupported usage for ECH") -} - -func (c *echServerConfig) Client(conn net.Conn) (Conn, error) { - return &echConnWrapper{cftls.Client(conn, c.config)}, nil -} - -func (c *echServerConfig) Server(conn net.Conn) (Conn, error) { - return &echConnWrapper{cftls.Server(conn, c.config)}, nil -} - -func (c *echServerConfig) Clone() Config { - return &echServerConfig{ - config: c.config.Clone(), - } -} - -func (c *echServerConfig) Start() error { - err := c.startWatcher() - if err != nil { - c.logger.Warn("create credentials watcher: ", err) - } - return nil -} - -func (c *echServerConfig) startWatcher() error { - var watchPath []string - if c.certificatePath != "" { - watchPath = append(watchPath, c.certificatePath) - } - if c.keyPath != "" { - watchPath = append(watchPath, c.keyPath) - } - if c.echKeyPath != "" { - watchPath = append(watchPath, c.echKeyPath) - } - if len(watchPath) == 0 { - return nil - } - watcher, err := fswatch.NewWatcher(fswatch.Options{ - Path: watchPath, - Callback: func(path string) { - err := c.credentialsUpdated(path) - if err != nil { - c.logger.Error(E.Cause(err, "reload credentials")) - } - }, - }) - if err != nil { - return err - } - err = watcher.Start() - if err != nil { - return err - } - c.watcher = watcher - return nil -} - -func (c *echServerConfig) credentialsUpdated(path string) error { - if path == c.certificatePath || path == c.keyPath { - if path == c.certificatePath { - certificate, err := os.ReadFile(c.certificatePath) - if err != nil { - return err - } - c.certificate = certificate - } else { - key, err := os.ReadFile(c.keyPath) - if err != nil { - return err - } - c.key = key - } - keyPair, err := cftls.X509KeyPair(c.certificate, c.key) - if err != nil { - return E.Cause(err, "parse key pair") - } - c.config.Certificates = []cftls.Certificate{keyPair} - c.logger.Info("reloaded TLS certificate") - } else { - echKeyContent, err := os.ReadFile(c.echKeyPath) - if err != nil { - return err - } - block, rest := pem.Decode(echKeyContent) - if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 { - return E.New("invalid ECH keys pem") - } - echKeys, err := cftls.EXP_UnmarshalECHKeys(block.Bytes) - if err != nil { - return E.Cause(err, "parse ECH keys") - } - echKeySet, err := cftls.EXP_NewECHKeySet(echKeys) - if err != nil { - return E.Cause(err, "create ECH key set") - } - c.config.ServerECHProvider = echKeySet - c.logger.Info("reloaded ECH keys") - } - return nil -} - -func (c *echServerConfig) Close() error { - var err error - if c.watcher != nil { - err = E.Append(err, c.watcher.Close(), func(err error) error { - return E.Cause(err, "close credentials watcher") - }) - } - return err -} - -func NewECHServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { - if !options.Enabled { - return nil, nil - } - var tlsConfig cftls.Config - if options.ACME != nil && len(options.ACME.Domain) > 0 { - return nil, E.New("acme is unavailable in ech") - } - tlsConfig.Time = ntp.TimeFuncFromContext(ctx) - if options.ServerName != "" { - tlsConfig.ServerName = options.ServerName - } - if len(options.ALPN) > 0 { - tlsConfig.NextProtos = append(options.ALPN, tlsConfig.NextProtos...) - } - if options.MinVersion != "" { - minVersion, err := ParseTLSVersion(options.MinVersion) - if err != nil { - return nil, E.Cause(err, "parse min_version") - } - tlsConfig.MinVersion = minVersion - } - if options.MaxVersion != "" { - maxVersion, err := ParseTLSVersion(options.MaxVersion) - if err != nil { - return nil, E.Cause(err, "parse max_version") - } - tlsConfig.MaxVersion = maxVersion - } - if options.CipherSuites != nil { - find: - for _, cipherSuite := range options.CipherSuites { - for _, tlsCipherSuite := range tls.CipherSuites() { - if cipherSuite == tlsCipherSuite.Name { - tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID) - continue find - } - } - return nil, E.New("unknown cipher_suite: ", cipherSuite) - } - } - var certificate []byte - var key []byte - if len(options.Certificate) > 0 { - certificate = []byte(strings.Join(options.Certificate, "\n")) - } else if options.CertificatePath != "" { - content, err := os.ReadFile(options.CertificatePath) - if err != nil { - return nil, E.Cause(err, "read certificate") - } - certificate = content - } - if len(options.Key) > 0 { - key = []byte(strings.Join(options.Key, "\n")) - } else if options.KeyPath != "" { - content, err := os.ReadFile(options.KeyPath) - if err != nil { - return nil, E.Cause(err, "read key") - } - key = content - } - - if certificate == nil { - return nil, E.New("missing certificate") - } else if key == nil { - return nil, E.New("missing key") - } - - keyPair, err := cftls.X509KeyPair(certificate, key) - if err != nil { - return nil, E.Cause(err, "parse x509 key pair") - } - tlsConfig.Certificates = []cftls.Certificate{keyPair} - - var echKey []byte - if len(options.ECH.Key) > 0 { - echKey = []byte(strings.Join(options.ECH.Key, "\n")) - } else if options.ECH.KeyPath != "" { - content, err := os.ReadFile(options.ECH.KeyPath) - if err != nil { - return nil, E.Cause(err, "read ECH key") - } - echKey = content - } else { - return nil, E.New("missing ECH key") - } - - block, rest := pem.Decode(echKey) - if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 { - return nil, E.New("invalid ECH keys pem") - } - - echKeys, err := cftls.EXP_UnmarshalECHKeys(block.Bytes) - if err != nil { - return nil, E.Cause(err, "parse ECH keys") - } - - echKeySet, err := cftls.EXP_NewECHKeySet(echKeys) - if err != nil { - return nil, E.Cause(err, "create ECH key set") - } - - tlsConfig.ECHEnabled = true - tlsConfig.PQSignatureSchemesEnabled = options.ECH.PQSignatureSchemesEnabled - tlsConfig.DynamicRecordSizingDisabled = options.ECH.DynamicRecordSizingDisabled - tlsConfig.ServerECHProvider = echKeySet - - return &echServerConfig{ - config: &tlsConfig, - logger: logger, - certificate: certificate, - key: key, - certificatePath: options.CertificatePath, - keyPath: options.KeyPath, - echKeyPath: options.ECH.KeyPath, - }, nil -} diff --git a/common/tls/ech_stub.go b/common/tls/ech_stub.go index 4ee4272c..8c93690c 100644 --- a/common/tls/ech_stub.go +++ b/common/tls/ech_stub.go @@ -1,25 +1,23 @@ -//go:build !with_ech +//go:build !go1.24 package tls import ( "context" + "crypto/tls" - "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" ) -var errECHNotIncluded = E.New(`ECH is not included in this build, rebuild with -tags with_ech`) - -func NewECHServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { - return nil, errECHNotIncluded +func parseECHClientConfig(ctx context.Context, options option.OutboundTLSOptions, tlsConfig *tls.Config) (Config, error) { + return nil, E.New("ECH requires go1.24, please recompile your binary.") } -func NewECHClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) { - return nil, errECHNotIncluded +func parseECHServerConfig(ctx context.Context, options option.InboundTLSOptions, tlsConfig *tls.Config, echKeyPath *string) error { + return E.New("ECH requires go1.24, please recompile your binary.") } -func ECHKeygenDefault(host string, pqSignatureSchemesEnabled bool) (configPem string, keyPem string, err error) { - return "", "", errECHNotIncluded +func reloadECHKeys(echKeyPath string, tlsConfig *tls.Config) error { + return E.New("ECH requires go1.24, please recompile your binary.") } diff --git a/common/tls/mkcert.go b/common/tls/mkcert.go index 12680c48..4e0ed102 100644 --- a/common/tls/mkcert.go +++ b/common/tls/mkcert.go @@ -12,6 +12,9 @@ import ( ) func GenerateKeyPair(parent *x509.Certificate, parentKey any, timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { + if timeFunc == nil { + timeFunc = time.Now + } privateKeyPem, publicKeyPem, err := GenerateCertificate(parent, parentKey, timeFunc, serverName, timeFunc().Add(time.Hour)) if err != nil { return nil, err @@ -24,9 +27,6 @@ func GenerateKeyPair(parent *x509.Certificate, parentKey any, timeFunc func() ti } func GenerateCertificate(parent *x509.Certificate, parentKey any, timeFunc func() time.Time, serverName string, expire time.Time) (privateKeyPem []byte, publicKeyPem []byte, err error) { - if timeFunc == nil { - timeFunc = time.Now - } key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return diff --git a/common/tls/server.go b/common/tls/server.go index 6afd89d6..bcc5ddfa 100644 --- a/common/tls/server.go +++ b/common/tls/server.go @@ -16,13 +16,10 @@ func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLS if !options.Enabled { return nil, nil } - if options.ECH != nil && options.ECH.Enabled { - return NewECHServer(ctx, logger, options) - } else if options.Reality != nil && options.Reality.Enabled { + if options.Reality != nil && options.Reality.Enabled { return NewRealityServer(ctx, logger, options) - } else { - return NewSTDServer(ctx, logger, options) } + return NewSTDServer(ctx, logger, options) } func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) { diff --git a/common/tls/std_client.go b/common/tls/std_client.go index 78f4e5cf..8e9327bf 100644 --- a/common/tls/std_client.go +++ b/common/tls/std_client.go @@ -127,5 +127,8 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb } tlsConfig.RootCAs = certPool } + if options.ECH != nil && options.ECH.Enabled { + return parseECHClientConfig(ctx, options, &tlsConfig) + } return &STDClientConfig{&tlsConfig}, nil } diff --git a/common/tls/std_server.go b/common/tls/std_server.go index c8dcfbf5..04b7cfea 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -26,6 +26,7 @@ type STDServerConfig struct { key []byte certificatePath string keyPath string + echKeyPath string watcher *fswatch.Watcher } @@ -94,6 +95,9 @@ func (c *STDServerConfig) startWatcher() error { if c.keyPath != "" { watchPath = append(watchPath, c.keyPath) } + if c.echKeyPath != "" { + watchPath = append(watchPath, c.echKeyPath) + } watcher, err := fswatch.NewWatcher(fswatch.Options{ Path: watchPath, Callback: func(path string) { @@ -115,25 +119,33 @@ func (c *STDServerConfig) startWatcher() error { } func (c *STDServerConfig) certificateUpdated(path string) error { - if path == c.certificatePath { - certificate, err := os.ReadFile(c.certificatePath) - if err != nil { - return E.Cause(err, "reload certificate from ", c.certificatePath) + if path == c.certificatePath || path == c.keyPath { + if path == c.certificatePath { + certificate, err := os.ReadFile(c.certificatePath) + if err != nil { + return E.Cause(err, "reload certificate from ", c.certificatePath) + } + c.certificate = certificate + } else if path == c.keyPath { + key, err := os.ReadFile(c.keyPath) + if err != nil { + return E.Cause(err, "reload key from ", c.keyPath) + } + c.key = key } - c.certificate = certificate - } else if path == c.keyPath { - key, err := os.ReadFile(c.keyPath) + keyPair, err := tls.X509KeyPair(c.certificate, c.key) if err != nil { - return E.Cause(err, "reload key from ", c.keyPath) + return E.Cause(err, "reload key pair") } - c.key = key + c.config.Certificates = []tls.Certificate{keyPair} + c.logger.Info("reloaded TLS certificate") + } else if path == c.echKeyPath { + err := reloadECHKeys(c.echKeyPath, c.config) + if err != nil { + return err + } + c.logger.Info("reloaded ECH keys") } - keyPair, err := tls.X509KeyPair(c.certificate, c.key) - if err != nil { - return E.Cause(err, "reload key pair") - } - c.config.Certificates = []tls.Certificate{keyPair} - c.logger.Info("reloaded TLS certificate") return nil } @@ -238,6 +250,13 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound tlsConfig.Certificates = []tls.Certificate{keyPair} } } + var echKeyPath string + if options.ECH != nil && options.ECH.Enabled { + err = parseECHServerConfig(ctx, options, tlsConfig, &echKeyPath) + if err != nil { + return nil, err + } + } return &STDServerConfig{ config: tlsConfig, logger: logger, @@ -246,5 +265,6 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound key: key, certificatePath: options.CertificatePath, keyPath: options.KeyPath, + echKeyPath: echKeyPath, }, nil } diff --git a/docs/configuration/shared/tls.md b/docs/configuration/shared/tls.md index f2a716a7..e4d77718 100644 --- a/docs/configuration/shared/tls.md +++ b/docs/configuration/shared/tls.md @@ -1,3 +1,12 @@ +--- +icon: material/alert-decagram +--- + +!!! quote "Changes in sing-box 1.12.0" + + :material-delete-clock: [ech.pq_signature_schemes_enabled](#pq_signature_schemes_enabled) + :material-delete-clock: [ech.dynamic_record_sizing_disabled](#dynamic_record_sizing_disabled) + !!! quote "Changes in sing-box 1.10.0" :material-alert-decagram: [utls](#utls) @@ -34,10 +43,13 @@ }, "ech": { "enabled": false, - "pq_signature_schemes_enabled": false, - "dynamic_record_sizing_disabled": false, "key": [], - "key_path": "" + "key_path": "", + + // Deprecated + + "pq_signature_schemes_enabled": false, + "dynamic_record_sizing_disabled": false }, "reality": { "enabled": false, @@ -72,10 +84,12 @@ "certificate_path": "", "ech": { "enabled": false, - "pq_signature_schemes_enabled": false, - "dynamic_record_sizing_disabled": false, "config": [], - "config_path": "" + "config_path": "", + + // Deprecated + "pq_signature_schemes_enabled": false, + "dynamic_record_sizing_disabled": false }, "utls": { "enabled": false, @@ -246,16 +260,22 @@ Chrome fingerprint will be used if empty. ECH (Encrypted Client Hello) is a TLS extension that allows a client to encrypt the first part of its ClientHello message. -The ECH key and configuration can be generated by `sing-box generate ech-keypair [--pq-signature-schemes-enabled]`. +The ECH key and configuration can be generated by `sing-box generate ech-keypair`. #### pq_signature_schemes_enabled +!!! failure "Deprecated in sing-box 1.12.0" + + ECH support has been migrated to use stdlib in sing-box 1.12.0, which does not come with support for PQ signature schemes, so `pq_signature_schemes_enabled` has been deprecated and no longer works. + Enable support for post-quantum peer certificate signature schemes. -It is recommended to match the parameters of `sing-box generate ech-keypair`. - #### dynamic_record_sizing_disabled +!!! failure "Deprecated in sing-box 1.12.0" + + `dynamic_record_sizing_disabled` has nothing to do with ECH, was added by mistake, has been deprecated and no longer works. + Disables adaptive sizing of TLS records. When true, the largest possible TLS record size is always used. diff --git a/docs/configuration/shared/tls.zh.md b/docs/configuration/shared/tls.zh.md index 6cfc5f36..1418dd59 100644 --- a/docs/configuration/shared/tls.zh.md +++ b/docs/configuration/shared/tls.zh.md @@ -1,3 +1,12 @@ +--- +icon: material/alert-decagram +--- + +!!! quote "sing-box 1.12.0 中的更改" + + :material-delete-clock: [ech.pq_signature_schemes_enabled](#pq_signature_schemes_enabled) + :material-delete-clock: [ech.dynamic_record_sizing_disabled](#dynamic_record_sizing_disabled) + !!! quote "sing-box 1.10.0 中的更改" :material-alert-decagram: [utls](#utls) @@ -34,18 +43,21 @@ }, "ech": { "enabled": false, - "pq_signature_schemes_enabled": false, - "dynamic_record_sizing_disabled": false, "key": [], - "key_path": "" + "key_path": "", + + // 废弃的 + + "pq_signature_schemes_enabled": false, + "dynamic_record_sizing_disabled": false }, "reality": { "enabled": false, "handshake": { "server": "google.com", "server_port": 443, - ... - // 拨号字段 + + ... // 拨号字段 }, "private_key": "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc", "short_id": [ @@ -240,19 +252,6 @@ ECH (Encrypted Client Hello) 是一个 TLS 扩展,它允许客户端加密其 ECH 配置和密钥可以通过 `sing-box generate ech-keypair [--pq-signature-schemes-enabled]` 生成。 -#### pq_signature_schemes_enabled - -启用对后量子对等证书签名方案的支持。 - -建议匹配 `sing-box generate ech-keypair` 的参数。 - -#### dynamic_record_sizing_disabled - -禁用 TLS 记录的自适应大小调整。 - -如果为 true,则始终使用最大可能的 TLS 记录大小。 -如果为 false,则可能会调整 TLS 记录的大小以尝试改善延迟。 - #### key ==仅服务器== @@ -285,6 +284,27 @@ ECH PEM 配置路径 如果为空,将尝试从 DNS 加载。 +#### pq_signature_schemes_enabled + +!!! failure "已在 sing-box 1.12.0 废弃" + + ECH 支持已在 sing-box 1.12.0 迁移至使用标准库,但标准库不支持后量子对等证书签名方案,因此 `pq_signature_schemes_enabled` 已被弃用且不再工作。 + +启用对后量子对等证书签名方案的支持。 + +建议匹配 `sing-box generate ech-keypair` 的参数。 + +#### dynamic_record_sizing_disabled + +!!! failure "已在 sing-box 1.12.0 废弃" + + `dynamic_record_sizing_disabled` 与 ECH 无关,是错误添加的,现已弃用且不再工作。 + +禁用 TLS 记录的自适应大小调整。 + +如果为 true,则始终使用最大可能的 TLS 记录大小。 +如果为 false,则可能会调整 TLS 记录的大小以尝试改善延迟。 + ### ACME 字段 #### domain diff --git a/docs/deprecated.md b/docs/deprecated.md index 128c0709..8e53bda6 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -19,6 +19,17 @@ Legacy `outbound` DNS rules are deprecated and can be replaced by dial fields, check [Migration](../migration/#migrate-outbound-dns-rule-items-to-domain-resolver). +#### Legacy ECH fields + +ECH support has been migrated to use stdlib in sing-box 1.12.0, +which does not come with support for PQ signature schemes, +so `pq_signature_schemes_enabled` has been deprecated and no longer works. + +Also, `dynamic_record_sizing_disabled` has nothing to do with ECH, +was added by mistake, has been deprecated and no longer works. + +These fields will be removed in sing-box 1.13.0. + ## 1.11.0 #### Legacy special outbounds diff --git a/docs/deprecated.zh.md b/docs/deprecated.zh.md index 2c0f5578..c090432b 100644 --- a/docs/deprecated.zh.md +++ b/docs/deprecated.zh.md @@ -17,6 +17,15 @@ DNS 服务器已重构, 且可被拨号字段代替, 参阅 [迁移指南](/migration/#migrate-outbound-dns-rule-items-to-domain-resolver). +#### 旧的 ECH 字段 + +ECH 支持已在 sing-box 1.12.0 迁移至使用标准库,但标准库不支持后量子对等证书签名方案, +因此 `pq_signature_schemes_enabled` 已被弃用且不再工作。 + +另外,`dynamic_record_sizing_disabled` 与 ECH 无关,是错误添加的,现已弃用且不再工作。 + +相关字段将在 sing-box 1.13.0 中被移除。 + ## 1.11.0 #### 旧的特殊出站 diff --git a/docs/installation/build-from-source.md b/docs/installation/build-from-source.md index 8c4d4923..c286c366 100644 --- a/docs/installation/build-from-source.md +++ b/docs/installation/build-from-source.md @@ -6,19 +6,18 @@ icon: material/file-code ## :material-graph: Requirements +### sing-box 1.11 + +* Go 1.23.1 - ~ + ### sing-box 1.10 * Go 1.20.0 - ~ -* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled -* Go 1.21.0 - ~ with tag `with_ech` enabled ### sing-box 1.9 * Go 1.18.5 - 1.22.x * Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled -* Go 1.21.0 - 1.22.x with tag `with_ech` enabled - -You can download and install Go from: https://go.dev/doc/install, latest version is recommended. ## :material-fast-forward: Simple Build @@ -46,20 +45,19 @@ go build -tags "tag_a tag_b" ./cmd/sing-box ## :material-folder-settings: Build Tags -| Build Tag | Enabled by default | Description | -|------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). | -| `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). | -| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). | -| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). | -| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). | -| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). | -| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). | -| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). | -| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). | -| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). | -| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). | -| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). | +| Build Tag | Enabled by default | Description | +|------------------------------------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). | +| `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). | +| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). | +| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). | +| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). | +| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). | +| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). | +| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). | +| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). | +| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). | +| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). | | `with_tailscale` | :material-check: | Build with Tailscale support, see [Tailscale endpoint](/configuration/endpoint/tailscale) | It is not recommended to change the default build tag list unless you really know what you are adding. diff --git a/docs/installation/build-from-source.zh.md b/docs/installation/build-from-source.zh.md index 7de7fcf4..c0222929 100644 --- a/docs/installation/build-from-source.zh.md +++ b/docs/installation/build-from-source.zh.md @@ -6,10 +6,13 @@ icon: material/file-code ## :material-graph: 要求 +### sing-box 1.11 + +* Go 1.23.1 - ~ + ### sing-box 1.10 * Go 1.20.0 - ~ -* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled * Go 1.21.0 - ~ with tag `with_ech` enabled ### sing-box 1.9 @@ -52,7 +55,6 @@ go build -tags "tag_a tag_b" ./cmd/sing-box | `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). | | `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). | | `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). | -| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). | | `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). | | `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). | | `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). | diff --git a/experimental/deprecated/constants.go b/experimental/deprecated/constants.go index d5c3ca48..16216716 100644 --- a/experimental/deprecated/constants.go +++ b/experimental/deprecated/constants.go @@ -144,6 +144,7 @@ var OptionTUNGSO = Note{ DeprecatedVersion: "1.11.0", ScheduledVersion: "1.12.0", EnvName: "TUN_GSO", + MigrationLink: "https://sing-box.sagernet.org/deprecated/#gso-option-in-tun", } var OptionLegacyDNSTransport = Note{ @@ -179,6 +180,14 @@ var OptionMissingDomainResolver = Note{ MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver", } +var OptionLegacyECHOptions = Note{ + Name: "legacy-ech-options", + Description: "legacy ECH options", + DeprecatedVersion: "1.12.0", + ScheduledVersion: "1.13.0", + MigrationLink: "https://sing-box.sagernet.org/deprecated/#legacy-ech-fields", +} + var Options = []Note{ OptionBadMatchSource, OptionGEOIP, @@ -194,4 +203,5 @@ var Options = []Note{ OptionLegacyDNSFakeIPOptions, OptionOutboundDNSRuleItem, OptionMissingDomainResolver, + OptionLegacyECHOptions, } diff --git a/experimental/deprecated/stderr.go b/experimental/deprecated/stderr.go index f29b4754..0dfb9354 100644 --- a/experimental/deprecated/stderr.go +++ b/experimental/deprecated/stderr.go @@ -28,11 +28,15 @@ func (f *stderrManager) ReportDeprecated(feature Note) { f.logger.Warn(feature.MessageWithLink()) return } - enable, enableErr := strconv.ParseBool(os.Getenv("ENABLE_DEPRECATED_" + feature.EnvName)) - if enableErr == nil && enable { - f.logger.Warn(feature.MessageWithLink()) - return + if feature.EnvName != "" { + enable, enableErr := strconv.ParseBool(os.Getenv("ENABLE_DEPRECATED_" + feature.EnvName)) + if enableErr == nil && enable { + f.logger.Warn(feature.MessageWithLink()) + return + } + f.logger.Error(feature.MessageWithLink()) + f.logger.Fatal("to continuing using this feature, set environment variable ENABLE_DEPRECATED_" + feature.EnvName + "=true") + } else { + f.logger.Error(feature.MessageWithLink()) } - f.logger.Error(feature.MessageWithLink()) - f.logger.Fatal("to continuing using this feature, set environment variable ENABLE_DEPRECATED_" + feature.EnvName + "=true") } diff --git a/go.mod b/go.mod index 18c25300..0c89e65f 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,6 @@ require ( github.com/oschwald/maxminddb-golang v1.13.1 github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a - github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 github.com/sagernet/cors v1.2.1 github.com/sagernet/fswatch v0.1.1 github.com/sagernet/gomobile v0.1.4 diff --git a/go.sum b/go.sum index ebbe57cd..5abb0953 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,6 @@ github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 h1:qi+ijeREa0yfAaO github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1/go.mod h1:JULDuzTMn2gyZFcjpTVZP4/UuwAdbHJ0bum2RdjXojU= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= -github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY= -github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k= github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= diff --git a/option/tls.go b/option/tls.go index 72aaaef1..13e75306 100644 --- a/option/tls.go +++ b/option/tls.go @@ -83,19 +83,25 @@ type InboundRealityHandshakeOptions struct { } type InboundECHOptions struct { - Enabled bool `json:"enabled,omitempty"` - PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"` - DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"` - Key badoption.Listable[string] `json:"key,omitempty"` - KeyPath string `json:"key_path,omitempty"` + Enabled bool `json:"enabled,omitempty"` + Key badoption.Listable[string] `json:"key,omitempty"` + KeyPath string `json:"key_path,omitempty"` + + // Deprecated: not supported by stdlib + PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"` + // Deprecated: added by fault + DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"` } type OutboundECHOptions struct { - Enabled bool `json:"enabled,omitempty"` - PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"` - DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"` - Config badoption.Listable[string] `json:"config,omitempty"` - ConfigPath string `json:"config_path,omitempty"` + Enabled bool `json:"enabled,omitempty"` + Config badoption.Listable[string] `json:"config,omitempty"` + ConfigPath string `json:"config_path,omitempty"` + + // Deprecated: not supported by stdlib + PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"` + // Deprecated: added by fault + DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"` } type OutboundUTLSOptions struct { diff --git a/test/box_test.go b/test/box_test.go index 08b50b64..bfffaa03 100644 --- a/test/box_test.go +++ b/test/box_test.go @@ -32,7 +32,7 @@ func TestMain(m *testing.M) { var globalCtx context.Context func init() { - globalCtx = box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()) + globalCtx = box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), include.DNSTransportRegistry()) } func startInstance(t *testing.T, options option.Options) *box.Box { diff --git a/test/ech_test.go b/test/ech_test.go index 865ffba0..91d13d3a 100644 --- a/test/ech_test.go +++ b/test/ech_test.go @@ -15,7 +15,7 @@ import ( func TestECH(t *testing.T) { _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false)) + echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org")) startInstance(t, option.Options{ Inbounds: []option.Inbound{ { @@ -108,7 +108,7 @@ func TestECH(t *testing.T) { func TestECHQUIC(t *testing.T) { _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false)) + echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org")) startInstance(t, option.Options{ Inbounds: []option.Inbound{ { @@ -198,7 +198,7 @@ func TestECHQUIC(t *testing.T) { func TestECHHysteria2(t *testing.T) { _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false)) + echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org")) startInstance(t, option.Options{ Inbounds: []option.Inbound{ { diff --git a/test/go.mod b/test/go.mod index 68fddc34..2baf3b41 100644 --- a/test/go.mod +++ b/test/go.mod @@ -1,8 +1,8 @@ module test -go 1.23 +go 1.23.1 -toolchain go1.23.2 +toolchain go1.24.0 require github.com/sagernet/sing-box v0.0.0 @@ -11,110 +11,149 @@ replace github.com/sagernet/sing-box => ../ require ( github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 - github.com/gofrs/uuid/v5 v5.3.0 - github.com/sagernet/quic-go v0.48.2-beta.1 - github.com/sagernet/sing v0.6.0-beta.12 - github.com/sagernet/sing-dns v0.4.0-beta.2 - github.com/sagernet/sing-quic v0.4.0-beta.4 + github.com/gofrs/uuid/v5 v5.3.1 + github.com/sagernet/quic-go v0.49.0-beta.1 + github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff + github.com/sagernet/sing-quic v0.4.1-beta.1 github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/spyzhov/ajson v0.9.4 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 go.uber.org/goleak v1.3.0 - golang.org/x/net v0.31.0 + golang.org/x/net v0.35.0 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/andybalholm/brotli v1.0.6 // indirect - github.com/caddyserver/certmagic v0.20.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/akutz/memconn v0.1.0 // indirect + github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/anytls/sing-anytls v0.0.2 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/caddyserver/certmagic v0.21.7 // indirect + github.com/caddyserver/zerossl v0.1.3 // indirect + github.com/cloudflare/circl v1.6.0 // indirect + github.com/coder/websocket v1.8.12 // indirect github.com/containerd/log v0.1.0 // indirect + github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/cretz/bine v0.2.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect + github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-chi/chi/v5 v5.1.0 // indirect + github.com/fxamacker/cbor/v2 v2.6.0 // indirect + github.com/gaissmai/bart v0.11.1 // indirect + github.com/go-chi/chi/v5 v5.2.1 // indirect github.com/go-chi/render v1.0.3 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect + github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect + github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/csrf v1.7.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect - github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect - github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.17.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/hdevalence/ed25519consensus v0.2.0 // indirect + github.com/illarion/gonotify/v2 v2.0.3 // indirect + github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect + github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect + github.com/jsimonetti/rtnetlink v1.4.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/libdns/alidns v1.0.3 // indirect github.com/libdns/cloudflare v0.1.1 // indirect github.com/libdns/libdns v0.2.2 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect - github.com/mdlayher/socket v0.4.1 // indirect - github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa // indirect - github.com/mholt/acmez v1.2.0 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/mdlayher/sdnotify v1.0.0 // indirect + github.com/mdlayher/socket v0.5.1 // indirect + github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect + github.com/mholt/acmez/v3 v3.0.1 // indirect + github.com/miekg/dns v1.1.63 // indirect + github.com/mitchellh/go-ps v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/onsi/ginkgo/v2 v2.9.7 // indirect + github.com/onsi/ginkgo/v2 v2.17.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/oschwald/maxminddb-golang v1.12.0 // indirect - github.com/pierrec/lz4/v4 v4.1.14 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect + github.com/safchain/ethtool v0.3.0 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect - github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect github.com/sagernet/cors v1.2.1 // indirect github.com/sagernet/fswatch v0.1.1 // indirect github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing-mux v0.3.0-alpha.1 // indirect - github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 // indirect - github.com/sagernet/sing-tun v0.6.0-beta.8 // indirect - github.com/sagernet/sing-vmess v0.2.0-beta.2 // indirect + github.com/sagernet/sing-mux v0.3.1 // indirect + github.com/sagernet/sing-shadowtls v0.2.0 // indirect + github.com/sagernet/sing-tun v0.6.1 // indirect + github.com/sagernet/sing-vmess v0.2.0 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect + github.com/sagernet/tailscale v1.79.0-mod.1 // indirect github.com/sagernet/utls v1.6.7 // indirect github.com/sagernet/wireguard-go v0.0.1-beta.5 // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect - github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect + github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect + github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect + github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect + github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect + github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect + github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect + github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect + github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect + github.com/tcnksm/go-httpstat v0.2.0 // indirect + github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect github.com/vishvananda/netns v0.0.4 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect - go.opentelemetry.io/otel v1.31.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect - go.opentelemetry.io/otel/metric v1.31.0 // indirect - go.opentelemetry.io/otel/sdk v1.31.0 // indirect - go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect + go.uber.org/zap/exp v0.3.0 // indirect + go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/mod v0.20.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/term v0.29.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.24.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect - google.golang.org/grpc v1.67.1 // indirect - google.golang.org/protobuf v1.35.1 // indirect + golang.zx2c4.com/wireguard/windows v0.5.3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/grpc v1.70.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect diff --git a/test/go.sum b/test/go.sum index 5266d18c..d63f3057 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,24 +1,46 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= -github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= -github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= +github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= +github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/anytls/sing-anytls v0.0.2 h1:25azSh0o/LMcIkhS4ZutgRTIGwh8O3wuOhsThVM9K9o= +github.com/anytls/sing-anytls v0.0.2/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg= +github.com/caddyserver/certmagic v0.21.7/go.mod h1:LCPG3WLxcnjVKl/xpjzM0gqh0knrKKKiO5WVttX2eEI= +github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= +github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= +github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= +github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= +github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk= +github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= @@ -31,10 +53,18 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= +github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc= +github.com/gaissmai/bart v0.11.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= +github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= +github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -42,42 +72,63 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= -github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= +github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= +github.com/gofrs/uuid/v5 v5.3.1 h1:aPx49MwJbekCzOyhZDjJVb0hx3A0KLjlbLx6p2gY0p0= +github.com/gofrs/uuid/v5 v5.3.1/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= -github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= +github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= -github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= -github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/illarion/gonotify/v2 v2.0.3 h1:B6+SKPo/0Sw8cRJh1aLzNEeNVFfzE3c6N+o+vyxM+9A= +github.com/illarion/gonotify/v2 v2.0.3/go.mod h1:38oIJTgFqupkEydkkClkbL6i5lXV/bxdH9do5TALPEE= +github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= +github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= -github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= +github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= +github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I= +github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= +github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ= @@ -89,48 +140,56 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= -github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= -github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= -github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa h1:9mcjV+RGZVC3reJBNDjjNPyS8PmFG97zq56X7WNaFO4= -github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa/go.mod h1:4tLB5c8U0CxpkFM+AJJB77jEaVDbLH5XQvy42vAGsWw= -github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= -github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= +github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= +github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= +github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= +github.com/mholt/acmez/v3 v3.0.1 h1:4PcjKjaySlgXK857aTfDuRbmnM5gb3Ruz3tvoSJAUp8= +github.com/mholt/acmez/v3 v3.0.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= +github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= -github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= -github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= +github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= +github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= -github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY= -github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k= github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= @@ -141,31 +200,31 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.48.2-beta.1 h1:W0plrLWa1XtOWDTdX3CJwxmQuxkya12nN5BRGZ87kEg= -github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k= +github.com/sagernet/quic-go v0.49.0-beta.1 h1:3LdoCzVVfYRibZns1tYWSIoB65fpTmrwy+yfK8DQ8Jk= +github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8WHNsRs71b3Lt1+p/U= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.6.0-beta.12 h1:2DnTJcvypK3/PM/8JjmgG8wVK48gdcpRwU98c4J/a7s= -github.com/sagernet/sing v0.6.0-beta.12/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-dns v0.4.0-beta.2 h1:HW94bUEp7K/vf5DlYz646LTZevQtJ0250jZa/UZRlbY= -github.com/sagernet/sing-dns v0.4.0-beta.2/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8= -github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg= -github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE= -github.com/sagernet/sing-quic v0.4.0-beta.4 h1:kKiMLGaxvVLDCSvCMYo4PtWd1xU6FTL7xvUAQfXO09g= -github.com/sagernet/sing-quic v0.4.0-beta.4/go.mod h1:1UNObFodd8CnS3aCT53x9cigjPSCl3P//8dfBMCwBDM= +github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff h1:5UGghwx8cI14qFa0ienrLekAYfhdKAiWvJUkY7rHmsI= +github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= +github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78= +github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s= +github.com/sagernet/sing-quic v0.4.1-beta.1/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= -github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjSsZtRPxiyLV6jyKg0= -github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA= -github.com/sagernet/sing-tun v0.6.0-beta.8 h1:GFNt/w8r1v30zC/hfCytk8C9+N/f1DfvosFXJkyJlrw= -github.com/sagernet/sing-tun v0.6.0-beta.8/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= -github.com/sagernet/sing-vmess v0.2.0-beta.2 h1:obAkAL35X7ql4RnGzDg4dBYIRpGXRKqcN4LyLZpZGSs= -github.com/sagernet/sing-vmess v0.2.0-beta.2/go.mod h1:HGhf9XUdeE2iOWrX0hQNFgXPbKyGlzpeYFyX0c/pykk= +github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk= +github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= +github.com/sagernet/sing-tun v0.6.1 h1:4l0+gnEKcGjlWfUVTD+W0BRApqIny/lU2ZliurE+VMo= +github.com/sagernet/sing-tun v0.6.1/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= +github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI= +github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= +github.com/sagernet/tailscale v1.79.0-mod.1 h1:wIuAH7VqBYJNk0h2+bTyk4F0OlSqHvyLDCBrD3i+XNI= +github.com/sagernet/tailscale v1.79.0-mod.1/go.mod h1:RKY5WjYLj3JJ7VO/8ZCw8eAFa4+kWU6A1Ftdk84uB14= github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8= github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM= github.com/sagernet/wireguard-go v0.0.1-beta.5 h1:aBEsxJUMEONwOZqKPIkuAcv4zJV5p6XlzEN04CF0FXc= @@ -177,36 +236,60 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/spyzhov/ajson v0.9.4 h1:MVibcTCgO7DY4IlskdqIlCmDOsUOZ9P7oKj8ifdcf84= github.com/spyzhov/ajson v0.9.4/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= +github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= +github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= +github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw= +github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= +github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= +github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= +github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= +github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= +github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU= +github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= +github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w= +github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU= +github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 h1:tdUdyPqJ0C97SJfjB9tW6EylTtreyee9C44de+UBG0g= +github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= +github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= +github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= +github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= +github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= +github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e h1:BA9O3BmlTmpjbvajAwzWx4Wo2TRVdpPXZEeemGQcajw= +github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= -go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= -go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= -go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= -go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= -go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -215,53 +298,63 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= +go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= +go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= +go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -276,17 +369,19 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= -google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= -google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= +google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E= +google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -294,3 +389,5 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= From 7d028a9b29ee8d6df8b51023951d71db5b66bc7a Mon Sep 17 00:00:00 2001 From: anytls Date: Thu, 20 Feb 2025 20:06:21 +0800 Subject: [PATCH 56/62] Add AnyTLS protocol --- constant/proxy.go | 1 + docs/configuration/inbound/anytls.md | 39 +++++++ docs/configuration/inbound/anytls.zh.md | 39 +++++++ docs/configuration/inbound/index.md | 1 + docs/configuration/inbound/index.zh.md | 1 + docs/configuration/outbound/anytls.md | 55 +++++++++ docs/configuration/outbound/anytls.zh.md | 55 +++++++++ docs/configuration/outbound/index.md | 1 + docs/configuration/outbound/index.zh.md | 1 + go.mod | 1 + go.sum | 4 + include/registry.go | 3 + option/anytls.go | 24 ++++ protocol/anytls/inbound.go | 135 +++++++++++++++++++++++ protocol/anytls/outbound.go | 129 ++++++++++++++++++++++ 15 files changed, 489 insertions(+) create mode 100644 docs/configuration/inbound/anytls.md create mode 100644 docs/configuration/inbound/anytls.zh.md create mode 100644 docs/configuration/outbound/anytls.md create mode 100644 docs/configuration/outbound/anytls.zh.md create mode 100644 option/anytls.go create mode 100644 protocol/anytls/inbound.go create mode 100644 protocol/anytls/outbound.go diff --git a/constant/proxy.go b/constant/proxy.go index 45e79f84..787a1243 100644 --- a/constant/proxy.go +++ b/constant/proxy.go @@ -19,6 +19,7 @@ const ( TypeTor = "tor" TypeSSH = "ssh" TypeShadowTLS = "shadowtls" + TypeAnyTLS = "anytls" TypeShadowsocksR = "shadowsocksr" TypeVLESS = "vless" TypeTUIC = "tuic" diff --git a/docs/configuration/inbound/anytls.md b/docs/configuration/inbound/anytls.md new file mode 100644 index 00000000..ce4eefe6 --- /dev/null +++ b/docs/configuration/inbound/anytls.md @@ -0,0 +1,39 @@ +### Structure + +```json +{ + "type": "anytls", + "tag": "anytls-in", + + ... // Listen Fields + + "users": [ + { + "name": "sekai", + "password": "8JCsPssfgS8tiRwiMlhARg==" + } + ], + "padding_scheme": [], + "tls": {} +} +``` + +### Listen Fields + +See [Listen Fields](/configuration/shared/listen/) for details. + +### Fields + +#### users + +==Required== + +AnyTLS users. + +#### padding_scheme + +AnyTLS padding scheme line array. + +#### tls + +TLS configuration, see [TLS](/configuration/shared/tls/#inbound). diff --git a/docs/configuration/inbound/anytls.zh.md b/docs/configuration/inbound/anytls.zh.md new file mode 100644 index 00000000..27e78ba4 --- /dev/null +++ b/docs/configuration/inbound/anytls.zh.md @@ -0,0 +1,39 @@ +### 结构 + +```json +{ + "type": "anytls", + "tag": "anytls-in", + + ... // 监听字段 + + "users": [ + { + "name": "sekai", + "password": "8JCsPssfgS8tiRwiMlhARg==" + } + ], + "padding_scheme": [], + "tls": {} +} +``` + +### 监听字段 + +参阅 [监听字段](/zh/configuration/shared/listen/)。 + +### 字段 + +#### users + +==必填== + +AnyTLS 用户。 + +#### padding_scheme + +AnyTLS 填充方案行数组。 + +#### tls + +TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 diff --git a/docs/configuration/inbound/index.md b/docs/configuration/inbound/index.md index 9ff4a7cf..27cc9fdb 100644 --- a/docs/configuration/inbound/index.md +++ b/docs/configuration/inbound/index.md @@ -30,6 +30,7 @@ | `tuic` | [TUIC](./tuic/) | :material-close: | | `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: | | `vless` | [VLESS](./vless/) | TCP | +| `anytls` | [AnyTLS](./anytls/) | TCP | | `tun` | [Tun](./tun/) | :material-close: | | `redirect` | [Redirect](./redirect/) | :material-close: | | `tproxy` | [TProxy](./tproxy/) | :material-close: | diff --git a/docs/configuration/inbound/index.zh.md b/docs/configuration/inbound/index.zh.md index 2c036340..1e0c0c4f 100644 --- a/docs/configuration/inbound/index.zh.md +++ b/docs/configuration/inbound/index.zh.md @@ -30,6 +30,7 @@ | `tuic` | [TUIC](./tuic/) | :material-close: | | `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: | | `vless` | [VLESS](./vless/) | TCP | +| `anytls` | [AnyTLS](./anytls/) | TCP | | `tun` | [Tun](./tun/) | :material-close: | | `redirect` | [Redirect](./redirect/) | :material-close: | | `tproxy` | [TProxy](./tproxy/) | :material-close: | diff --git a/docs/configuration/outbound/anytls.md b/docs/configuration/outbound/anytls.md new file mode 100644 index 00000000..42ee51d9 --- /dev/null +++ b/docs/configuration/outbound/anytls.md @@ -0,0 +1,55 @@ +### Structure + +```json +{ + "type": "anytls", + "tag": "anytls-out", + + "server": "127.0.0.1", + "server_port": 1080, + "password": "8JCsPssfgS8tiRwiMlhARg==", + "idle_session_check_interval": "30s", + "idle_session_timeout": "30s", + "tls": {}, + + ... // Dial Fields +} +``` + +### Fields + +#### server + +==Required== + +The server address. + +#### server_port + +==Required== + +The server port. + +#### password + +==Required== + +The AnyTLS password. + +#### idle_session_check_interval + +Interval checking for idle sessions. Default: 30s. + +#### idle_session_timeout + +In the check, close sessions that have been idle for longer than this. Default: 30s. + +#### tls + +==Required== + +TLS configuration, see [TLS](/configuration/shared/tls/#outbound). + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial/) for details. diff --git a/docs/configuration/outbound/anytls.zh.md b/docs/configuration/outbound/anytls.zh.md new file mode 100644 index 00000000..4f6421df --- /dev/null +++ b/docs/configuration/outbound/anytls.zh.md @@ -0,0 +1,55 @@ +### 结构 + +```json +{ + "type": "anytls", + "tag": "anytls-out", + + "server": "127.0.0.1", + "server_port": 1080, + "password": "8JCsPssfgS8tiRwiMlhARg==", + "idle_session_check_interval": "30s", + "idle_session_timeout": "30s", + "tls": {}, + + ... // 拨号字段 +} +``` + +### 字段 + +#### server + +==必填== + +服务器地址。 + +#### server_port + +==必填== + +服务器端口。 + +#### password + +==必填== + +AnyTLS 密码。 + +#### idle_session_check_interval + +检查空闲会话的时间间隔。默认值:30秒。 + +#### idle_session_timeout + +在检查中,关闭闲置时间超过此值的会话。默认值:30秒。 + +#### tls + +==必填== + +TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。 + +### 拨号字段 + +参阅 [拨号字段](/zh/configuration/shared/dial/)。 diff --git a/docs/configuration/outbound/index.md b/docs/configuration/outbound/index.md index c5dc2917..b6094a15 100644 --- a/docs/configuration/outbound/index.md +++ b/docs/configuration/outbound/index.md @@ -30,6 +30,7 @@ | `shadowtls` | [ShadowTLS](./shadowtls/) | | `tuic` | [TUIC](./tuic/) | | `hysteria2` | [Hysteria2](./hysteria2/) | +| `anytls` | [AnyTLS](./anytls/) | | `tor` | [Tor](./tor/) | | `ssh` | [SSH](./ssh/) | | `dns` | [DNS](./dns/) | diff --git a/docs/configuration/outbound/index.zh.md b/docs/configuration/outbound/index.zh.md index c7ee59e9..1b6066e7 100644 --- a/docs/configuration/outbound/index.zh.md +++ b/docs/configuration/outbound/index.zh.md @@ -30,6 +30,7 @@ | `shadowtls` | [ShadowTLS](./shadowtls/) | | `tuic` | [TUIC](./tuic/) | | `hysteria2` | [Hysteria2](./hysteria2/) | +| `anytls` | [AnyTLS](./anytls/) | | `tor` | [Tor](./tor/) | | `ssh` | [SSH](./ssh/) | | `dns` | [DNS](./dns/) | diff --git a/go.mod b/go.mod index 0c89e65f..bf45b4d6 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/sagernet/sing-box go 1.23.1 require ( + github.com/anytls/sing-anytls v0.0.2 github.com/caddyserver/certmagic v0.21.7 github.com/cloudflare/circl v1.6.0 github.com/cretz/bine v0.2.0 diff --git a/go.sum b/go.sum index 5abb0953..a4638116 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,10 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/anytls/sing-anytls v0.0.1 h1:Hex6GFUcgATWMWL2E9YgH/7oPgwdokiIF09UQi5BEC0= +github.com/anytls/sing-anytls v0.0.1/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= +github.com/anytls/sing-anytls v0.0.2 h1:25azSh0o/LMcIkhS4ZutgRTIGwh8O3wuOhsThVM9K9o= +github.com/anytls/sing-anytls v0.0.2/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg= diff --git a/include/registry.go b/include/registry.go index 866c506a..87aea576 100644 --- a/include/registry.go +++ b/include/registry.go @@ -15,6 +15,7 @@ import ( "github.com/sagernet/sing-box/dns/transport/local" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-box/protocol/anytls" "github.com/sagernet/sing-box/protocol/block" "github.com/sagernet/sing-box/protocol/direct" protocolDNS "github.com/sagernet/sing-box/protocol/dns" @@ -53,6 +54,7 @@ func InboundRegistry() *inbound.Registry { naive.RegisterInbound(registry) shadowtls.RegisterInbound(registry) vless.RegisterInbound(registry) + anytls.RegisterInbound(registry) registerQUICInbounds(registry) registerStubForRemovedInbounds(registry) @@ -80,6 +82,7 @@ func OutboundRegistry() *outbound.Registry { ssh.RegisterOutbound(registry) shadowtls.RegisterOutbound(registry) vless.RegisterOutbound(registry) + anytls.RegisterOutbound(registry) registerQUICOutbounds(registry) registerWireGuardOutbound(registry) diff --git a/option/anytls.go b/option/anytls.go new file mode 100644 index 00000000..0ac19cd1 --- /dev/null +++ b/option/anytls.go @@ -0,0 +1,24 @@ +package option + +import "github.com/sagernet/sing/common/json/badoption" + +type AnyTLSInboundOptions struct { + ListenOptions + InboundTLSOptionsContainer + Users []AnyTLSUser `json:"users,omitempty"` + PaddingScheme badoption.Listable[string] `json:"padding_scheme,omitempty"` +} + +type AnyTLSUser struct { + Name string `json:"name,omitempty"` + Password string `json:"password,omitempty"` +} + +type AnyTLSOutboundOptions struct { + DialerOptions + ServerOptions + OutboundTLSOptionsContainer + Password string `json:"password,omitempty"` + IdleSessionCheckInterval badoption.Duration `json:"idle_session_check_interval,omitempty"` + IdleSessionTimeout badoption.Duration `json:"idle_session_timeout,omitempty"` +} diff --git a/protocol/anytls/inbound.go b/protocol/anytls/inbound.go new file mode 100644 index 00000000..89907f1d --- /dev/null +++ b/protocol/anytls/inbound.go @@ -0,0 +1,135 @@ +package anytls + +import ( + "context" + "net" + "strings" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/adapter/inbound" + "github.com/sagernet/sing-box/common/listener" + "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/uot" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/auth" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + anytls "github.com/anytls/sing-anytls" + "github.com/anytls/sing-anytls/padding" +) + +func RegisterInbound(registry *inbound.Registry) { + inbound.Register[option.AnyTLSInboundOptions](registry, C.TypeAnyTLS, NewInbound) +} + +type Inbound struct { + inbound.Adapter + tlsConfig tls.ServerConfig + router adapter.ConnectionRouterEx + logger logger.ContextLogger + listener *listener.Listener + service *anytls.Service +} + +func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.AnyTLSInboundOptions) (adapter.Inbound, error) { + inbound := &Inbound{ + Adapter: inbound.NewAdapter(C.TypeAnyTLS, tag), + router: uot.NewRouter(router, logger), + logger: logger, + } + + if options.TLS != nil && options.TLS.Enabled { + tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + if err != nil { + return nil, err + } + inbound.tlsConfig = tlsConfig + } + + paddingScheme := padding.DefaultPaddingScheme + if len(options.PaddingScheme) > 0 { + paddingScheme = []byte(strings.Join(options.PaddingScheme, "\n")) + } + + service, err := anytls.NewService(anytls.ServiceConfig{ + Users: common.Map(options.Users, func(it option.AnyTLSUser) anytls.User { + return (anytls.User)(it) + }), + PaddingScheme: paddingScheme, + Handler: (*inboundHandler)(inbound), + Logger: logger, + }) + if err != nil { + return nil, err + } + inbound.service = service + inbound.listener = listener.New(listener.Options{ + Context: ctx, + Logger: logger, + Network: []string{N.NetworkTCP}, + Listen: options.ListenOptions, + ConnectionHandler: inbound, + }) + return inbound, nil +} + +func (h *Inbound) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + if h.tlsConfig != nil { + err := h.tlsConfig.Start() + if err != nil { + return err + } + } + return h.listener.Start() +} + +func (h *Inbound) Close() error { + return common.Close(h.listener, h.tlsConfig) +} + +func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { + if h.tlsConfig != nil { + tlsConn, err := tls.ServerHandshake(ctx, conn, h.tlsConfig) + if err != nil { + N.CloseOnHandshakeFailure(conn, onClose, err) + h.logger.ErrorContext(ctx, E.Cause(err, "process connection from ", metadata.Source, ": TLS handshake")) + return + } + conn = tlsConn + } + err := h.service.NewConnection(adapter.WithContext(ctx, &metadata), conn, metadata.Source, onClose) + if err != nil { + N.CloseOnHandshakeFailure(conn, onClose, err) + h.logger.ErrorContext(ctx, E.Cause(err, "process connection from ", metadata.Source)) + } +} + +type inboundHandler Inbound + +func (h *inboundHandler) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { + var metadata adapter.InboundContext + metadata.Inbound = h.Tag() + metadata.InboundType = h.Type() + //nolint:staticcheck + metadata.InboundDetour = h.listener.ListenOptions().Detour + //nolint:staticcheck + metadata.InboundOptions = h.listener.ListenOptions().InboundOptions + metadata.Source = source + metadata.Destination = destination + if userName, _ := auth.UserFromContext[string](ctx); userName != "" { + metadata.User = userName + h.logger.InfoContext(ctx, "[", userName, "] inbound connection to ", metadata.Destination) + } else { + h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) + } + h.router.RouteConnectionEx(ctx, conn, metadata, onClose) +} diff --git a/protocol/anytls/outbound.go b/protocol/anytls/outbound.go new file mode 100644 index 00000000..3a016d2e --- /dev/null +++ b/protocol/anytls/outbound.go @@ -0,0 +1,129 @@ +package anytls + +import ( + "context" + "net" + "os" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/adapter/outbound" + "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/uot" + + anytls "github.com/anytls/sing-anytls" +) + +func RegisterOutbound(registry *outbound.Registry) { + outbound.Register[option.AnyTLSOutboundOptions](registry, C.TypeAnyTLS, NewOutbound) +} + +type Outbound struct { + outbound.Adapter + dialer N.Dialer + server M.Socksaddr + tlsConfig tls.Config + client *anytls.Client + uotClient *uot.Client + logger log.ContextLogger +} + +func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.AnyTLSOutboundOptions) (adapter.Outbound, error) { + outbound := &Outbound{ + Adapter: outbound.NewAdapterWithDialerOptions(C.TypeAnyTLS, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), + server: options.ServerOptions.Build(), + logger: logger, + } + if options.TLS == nil || !options.TLS.Enabled { + return nil, C.ErrTLSRequired + } + + tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + if err != nil { + return nil, err + } + outbound.tlsConfig = tlsConfig + + outboundDialer, err := dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.DialerOptions, + }) + if err != nil { + return nil, err + } + outbound.dialer = outboundDialer + + client, err := anytls.NewClient(ctx, anytls.ClientConfig{ + Password: options.Password, + IdleSessionCheckInterval: options.IdleSessionCheckInterval.Build(), + IdleSessionTimeout: options.IdleSessionTimeout.Build(), + DialOut: outbound.dialOut, + Logger: logger, + }) + if err != nil { + return nil, err + } + outbound.client = client + + outbound.uotClient = &uot.Client{ + Dialer: (anytlsDialer)(client.CreateProxy), + Version: uot.Version, + } + return outbound, nil +} + +type anytlsDialer func(ctx context.Context, destination M.Socksaddr) (net.Conn, error) + +func (d anytlsDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + return d(ctx, destination) +} + +func (d anytlsDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + return nil, os.ErrInvalid +} + +func (h *Outbound) dialOut(ctx context.Context) (net.Conn, error) { + conn, err := h.dialer.DialContext(ctx, N.NetworkTCP, h.server) + if err != nil { + return nil, err + } + tlsConn, err := tls.ClientHandshake(ctx, conn, h.tlsConfig) + if err != nil { + common.Close(tlsConn, conn) + return nil, err + } + return tlsConn, nil +} + +func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + ctx, metadata := adapter.ExtendContext(ctx) + metadata.Outbound = h.Tag() + metadata.Destination = destination + switch N.NetworkName(network) { + case N.NetworkTCP: + h.logger.InfoContext(ctx, "outbound connection to ", destination) + return h.client.CreateProxy(ctx, destination) + case N.NetworkUDP: + h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination) + return h.uotClient.DialContext(ctx, network, destination) + } + return nil, os.ErrInvalid +} + +func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + ctx, metadata := adapter.ExtendContext(ctx) + metadata.Outbound = h.Tag() + metadata.Destination = destination + h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination) + return h.uotClient.ListenPacket(ctx, destination) +} + +func (h *Outbound) Close() error { + return common.Close(h.client) +} From 8d61c9b69da4ed85eb4870072118877826c52bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 22 Feb 2025 17:41:03 +0800 Subject: [PATCH 57/62] documentation: Fix AnyTLS doc --- docs/configuration/inbound/anytls.md | 20 ++++++++++++++++++++ docs/configuration/inbound/anytls.zh.md | 20 ++++++++++++++++++++ docs/configuration/outbound/anytls.md | 6 ++++++ docs/configuration/outbound/anytls.zh.md | 6 ++++++ mkdocs.yml | 2 ++ 5 files changed, 54 insertions(+) diff --git a/docs/configuration/inbound/anytls.md b/docs/configuration/inbound/anytls.md index ce4eefe6..7eca9434 100644 --- a/docs/configuration/inbound/anytls.md +++ b/docs/configuration/inbound/anytls.md @@ -1,3 +1,9 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + ### Structure ```json @@ -34,6 +40,20 @@ AnyTLS users. AnyTLS padding scheme line array. +Default padding scheme: + +``` +stop=8 +0=34-120 +1=100-400 +2=400-500,c,500-1000,c,400-500,c,500-1000,c,500-1000,c,400-500 +3=500-1000 +4=500-1000 +5=500-1000 +6=500-1000 +7=500-1000 +``` + #### tls TLS configuration, see [TLS](/configuration/shared/tls/#inbound). diff --git a/docs/configuration/inbound/anytls.zh.md b/docs/configuration/inbound/anytls.zh.md index 27e78ba4..5c119b72 100644 --- a/docs/configuration/inbound/anytls.zh.md +++ b/docs/configuration/inbound/anytls.zh.md @@ -1,3 +1,9 @@ +--- +icon: material/new-box +--- + +!!! question "自 sing-box 1.12.0 起" + ### 结构 ```json @@ -34,6 +40,20 @@ AnyTLS 用户。 AnyTLS 填充方案行数组。 +默认填充方案: + +``` +stop=8 +0=34-120 +1=100-400 +2=400-500,c,500-1000,c,400-500,c,500-1000,c,500-1000,c,400-500 +3=500-1000 +4=500-1000 +5=500-1000 +6=500-1000 +7=500-1000 +``` + #### tls TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 diff --git a/docs/configuration/outbound/anytls.md b/docs/configuration/outbound/anytls.md index 42ee51d9..d5eb8fdf 100644 --- a/docs/configuration/outbound/anytls.md +++ b/docs/configuration/outbound/anytls.md @@ -1,3 +1,9 @@ +--- +icon: material/new-box +--- + +!!! question "Since sing-box 1.12.0" + ### Structure ```json diff --git a/docs/configuration/outbound/anytls.zh.md b/docs/configuration/outbound/anytls.zh.md index 4f6421df..1d0828b1 100644 --- a/docs/configuration/outbound/anytls.zh.md +++ b/docs/configuration/outbound/anytls.zh.md @@ -1,3 +1,9 @@ +--- +icon: material/new-box +--- + +!!! question "自 sing-box 1.12.0 起" + ### 结构 ```json diff --git a/mkdocs.yml b/mkdocs.yml index e1a74fb0..f786ac84 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -144,6 +144,7 @@ nav: - VLESS: configuration/inbound/vless.md - TUIC: configuration/inbound/tuic.md - Hysteria2: configuration/inbound/hysteria2.md + - AnyTLS: configuration/inbound/anytls.md - Tun: configuration/inbound/tun.md - Redirect: configuration/inbound/redirect.md - TProxy: configuration/inbound/tproxy.md @@ -162,6 +163,7 @@ nav: - VLESS: configuration/outbound/vless.md - TUIC: configuration/outbound/tuic.md - Hysteria2: configuration/outbound/hysteria2.md + - AnyTLS: configuration/outbound/anytls.md - Tor: configuration/outbound/tor.md - SSH: configuration/outbound/ssh.md - DNS: configuration/outbound/dns.md From 8fe78e4f8842ca45a122080ef8111d2e918a4997 Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Sun, 23 Feb 2025 01:23:37 +0100 Subject: [PATCH 58/62] Fix Outbound deadlock --- adapter/outbound/manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adapter/outbound/manager.go b/adapter/outbound/manager.go index 977fe4ca..44ac8bc5 100644 --- a/adapter/outbound/manager.go +++ b/adapter/outbound/manager.go @@ -246,8 +246,6 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if err != nil { return err } - m.access.Lock() - defer m.access.Unlock() if m.started { for _, stage := range adapter.ListStartStages { err = adapter.LegacyStart(outbound, stage) @@ -256,6 +254,8 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. } } } + m.access.Lock() + defer m.access.Unlock() if existsOutbound, loaded := m.outboundByTag[tag]; loaded { if m.started { err = common.Close(existsOutbound) From 8dd9197687c641852a657a3232bf1a8a76ef421a Mon Sep 17 00:00:00 2001 From: libtry486 <89328481+libtry486@users.noreply.github.com> Date: Sun, 23 Feb 2025 08:27:41 +0800 Subject: [PATCH 59/62] documentation: Fix typo fix typo Signed-off-by: libtry486 <89328481+libtry486@users.noreply.github.com> --- docs/configuration/dns/server/udp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/dns/server/udp.md b/docs/configuration/dns/server/udp.md index 4ffbf4d8..c551d3c9 100644 --- a/docs/configuration/dns/server/udp.md +++ b/docs/configuration/dns/server/udp.md @@ -4,7 +4,7 @@ icon: material/new-box !!! question "Since sing-box 1.12.0" -# TCP +# UDP ### Structure From 048e72af718a3d93ab2ee59dc3d0e4bc68f24396 Mon Sep 17 00:00:00 2001 From: ReleTor <191429954+ReleTor@users.noreply.github.com> Date: Thu, 20 Feb 2025 17:39:39 +0800 Subject: [PATCH 60/62] documentation: Minor fixes --- docs/configuration/dns/server/http3.md | 2 +- docs/configuration/dns/server/https.md | 2 +- docs/configuration/dns/server/index.md | 26 ++++++------ docs/configuration/dns/server/index.zh.md | 46 +++++++++++++++++++++ docs/configuration/endpoint/index.md | 1 + docs/configuration/endpoint/index.zh.md | 5 ++- docs/configuration/endpoint/wireguard.zh.md | 2 +- docs/configuration/index.md | 2 + docs/configuration/index.zh.md | 2 + 9 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 docs/configuration/dns/server/index.zh.md diff --git a/docs/configuration/dns/server/http3.md b/docs/configuration/dns/server/http3.md index 89f000e8..dd81ba2d 100644 --- a/docs/configuration/dns/server/http3.md +++ b/docs/configuration/dns/server/http3.md @@ -50,7 +50,7 @@ If domain name is used, `domain_resolver` must also be set to resolve IP address The port of the DNS server. -`853` will be used by default. +`443` will be used by default. #### path diff --git a/docs/configuration/dns/server/https.md b/docs/configuration/dns/server/https.md index 93dc71a4..46e69a55 100644 --- a/docs/configuration/dns/server/https.md +++ b/docs/configuration/dns/server/https.md @@ -50,7 +50,7 @@ If domain name is used, `domain_resolver` must also be set to resolve IP address The port of the DNS server. -`853` will be used by default. +`443` will be used by default. #### path diff --git a/docs/configuration/dns/server/index.md b/docs/configuration/dns/server/index.md index 5393b0bd..0dae05c3 100644 --- a/docs/configuration/dns/server/index.md +++ b/docs/configuration/dns/server/index.md @@ -27,19 +27,19 @@ icon: material/alert-decagram The type of the DNS server. -| Type | Format | -|-----------------|-----------------------------------------------------| -| empty (default) | [Legacy](/configuration/dns/server/legacy/) | -| `tcp` | [TCP](/configuration/dns/server/tcp/) | -| `udp` | [UDP](/configuration/dns/server/udp/) | -| `tls` | [TLS](/configuration/dns/server/tls/) | -| `https` | [HTTPS](/configuration/dns/server/https/) | -| `quic` | [QUIC](/configuration/dns/server/quic/) | -| `h3` | [HTTP/3](/configuration/dns/server/http3/) | -| `predefined` | [Predefined](/configuration/dns/server/predefined/) | -| `dhcp` | [DHCP](/configuration/dns/server/dhcp/) | -| `fakeip` | [Fake IP](/configuration/dns/server/fakeip/) | - +| Type | Format | +|-----------------|-----------------------------| +| empty (default) | [Legacy](./legacy/) | +| `tcp` | [TCP](./tcp/) | +| `udp` | [UDP](./udp/) | +| `tls` | [TLS](./tls/) | +| `https` | [HTTPS](./https/) | +| `quic` | [QUIC](./quic/) | +| `h3` | [HTTP/3](./http3/) | +| `predefined` | [Predefined](./predefined/) | +| `dhcp` | [DHCP](./dhcp/) | +| `fakeip` | [Fake IP](./fakeip/) | +| `tailscale` | [Tailscale](./tailscale/) | #### tag diff --git a/docs/configuration/dns/server/index.zh.md b/docs/configuration/dns/server/index.zh.md new file mode 100644 index 00000000..2ad99502 --- /dev/null +++ b/docs/configuration/dns/server/index.zh.md @@ -0,0 +1,46 @@ +--- +icon: material/alert-decagram +--- + +!!! quote "sing-box 1.12.0 中的更改" + + :material-plus: [type](#type) + +# DNS Server + +### 结构 + +```json +{ + "dns": { + "servers": [ + { + "type": "", + "tag": "" + } + ] + } +} +``` + +#### type + +DNS 服务器的类型。 + +| 类型 | 格式 | +|-----------------|-----------------------------| +| empty (default) | [Legacy](./legacy/) | +| `tcp` | [TCP](./tcp/) | +| `udp` | [UDP](./udp/) | +| `tls` | [TLS](./tls/) | +| `https` | [HTTPS](./https/) | +| `quic` | [QUIC](./quic/) | +| `h3` | [HTTP/3](./http3/) | +| `predefined` | [Predefined](./predefined/) | +| `dhcp` | [DHCP](./dhcp/) | +| `fakeip` | [Fake IP](./fakeip/) | +| `tailscale` | [Tailscale](./tailscale/) | + +#### tag + +DNS 服务器的标签。 diff --git a/docs/configuration/endpoint/index.md b/docs/configuration/endpoint/index.md index e40333db..5e98c4cc 100644 --- a/docs/configuration/endpoint/index.md +++ b/docs/configuration/endpoint/index.md @@ -26,6 +26,7 @@ Endpoint is protocols that has both inbound and outbound behavior. | Type | Format | |-------------|---------------------------| | `wireguard` | [WireGuard](./wireguard/) | +| `tailscale` | [Tailscale](./tailscale/) | #### tag diff --git a/docs/configuration/endpoint/index.zh.md b/docs/configuration/endpoint/index.zh.md index 69ba2d09..3060a6e6 100644 --- a/docs/configuration/endpoint/index.zh.md +++ b/docs/configuration/endpoint/index.zh.md @@ -23,9 +23,10 @@ icon: material/new-box ### 字段 -| 类型 | 格式 | +| 类型 | 格式 | |-------------|---------------------------| -| `wireguard` | [WireGuard](./wiregaurd/) | +| `wireguard` | [WireGuard](./wiregaurd/) | +| `tailscale` | [Tailscale](./tailscale/) | #### tag diff --git a/docs/configuration/endpoint/wireguard.zh.md b/docs/configuration/endpoint/wireguard.zh.md index 918e7cbf..f80c82b4 100644 --- a/docs/configuration/endpoint/wireguard.zh.md +++ b/docs/configuration/endpoint/wireguard.zh.md @@ -41,7 +41,7 @@ icon: material/new-box ### 字段 -#### system_interface +#### system 使用系统设备。 diff --git a/docs/configuration/index.md b/docs/configuration/index.md index 05e6a87d..dc5d0637 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -9,6 +9,7 @@ sing-box uses JSON for configuration files. "log": {}, "dns": {}, "ntp": {}, + "certificate": {}, "endpoints": [], "inbounds": [], "outbounds": [], @@ -24,6 +25,7 @@ sing-box uses JSON for configuration files. | `log` | [Log](./log/) | | `dns` | [DNS](./dns/) | | `ntp` | [NTP](./ntp/) | +| `certificate` | [Certificate](./certificate/) | | `endpoints` | [Endpoint](./endpoint/) | | `inbounds` | [Inbound](./inbound/) | | `outbounds` | [Outbound](./outbound/) | diff --git a/docs/configuration/index.zh.md b/docs/configuration/index.zh.md index b639c72a..a18cefd8 100644 --- a/docs/configuration/index.zh.md +++ b/docs/configuration/index.zh.md @@ -9,6 +9,7 @@ sing-box 使用 JSON 作为配置文件格式。 "log": {}, "dns": {}, "ntp": {}, + "certificate": {}, "endpoints": [], "inbounds": [], "outbounds": [], @@ -24,6 +25,7 @@ sing-box 使用 JSON 作为配置文件格式。 | `log` | [日志](./log/) | | `dns` | [DNS](./dns/) | | `ntp` | [NTP](./ntp/) | +| `certificate` | [证书](./certificate/) | | `endpoints` | [端点](./endpoint/) | | `inbounds` | [入站](./inbound/) | | `outbounds` | [出站](./outbound/) | From dfb3afb50135fd4202b15bea1e12469dcb3f2e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 24 Feb 2025 07:23:46 +0800 Subject: [PATCH 61/62] documentation: Bump version --- docs/changelog.md | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index cf40c0ed..7b83d336 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,20 +2,135 @@ icon: material/alert-decagram --- +#### 1.12.0-alpha.12 + +* Fixes and improvements + ### 1.11.4 * Fixes and improvements +#### 1.12.0-alpha.11 + +* Fixes and improvements + +#### 1.12.0-alpha.10 + +* Add AnyTLS protocol **1** +* Improve `resolve` route action **2** +* Migrate to stdlib ECH implementation **3** +* Fixes and improvements + +**1**: + +The new AnyTLS protocol claims to mitigate TLS proxy traffic characteristics and comes with a new multiplexing scheme. + +See [AnyTLS Inbound](/configuration/inbound/anytls/) and [AnyTLS Outbound](/configuration/outbound/anytls/). + +**2**: + +`resolve` route action now accepts `disable_cache` and other options like in DNS route actions, see [Route Action](/configuration/route/rule_action). + +**3**: + +See [TLS](/configuration/shared/tls). + +The build tag `with_ech` is no longer needed and has been removed. + +#### 1.12.0-alpha.7 + +* Add Tailscale DNS server **1** +* Fixes and improvements + +**1**: + +See [Tailscale](/configuration/dns/server/tailscale/). + +#### 1.12.0-alpha.6 + +* Add Tailscale endpoint **1** +* Drop support for go1.22 **2** +* Fixes and improvements + +**1**: + +See [Tailscale](/configuration/endpoint/tailscale/). + +**2**: + +Due to maintenance difficulties, sing-box 1.12.0 requires at least Go 1.23 to compile. + +For Windows 7 users, legacy binaries now continue to compile with Go 1.23 and patches from [MetaCubeX/go](https://github.com/MetaCubeX/go). + ### 1.11.3 * Fixes and improvements _This version overwrites 1.11.2, as incorrect binaries were released due to a bug in the continuous integration process._ +#### 1.12.0-alpha.5 + +* Fixes and improvements + ### 1.11.1 * Fixes and improvements +#### 1.12.0-alpha.2 + +* Update quic-go to v0.49.0 +* Fixes and improvements + +#### 1.12.0-alpha.1 + +* Refactor DNS servers **1** +* Add domain resolver options**2** +* Add TLS fragment route options **3** +* Add certificate options **4** + +**1**: + +DNS servers are refactored for better performance and scalability. + +See [DNS server](/configuration/dns/server/). + +For migration, see [Migrate to new DNS server formats](/migration/#migrate-to-new-dns-servers). + +Compatibility for old formats will be removed in sing-box 1.14.0. + +**2**: + +Legacy `outbound` DNS rules are deprecated +and can be replaced by the new `domain_resolver` option. + +See [Dial Fields](/configuration/shared/dial/#domain_resolver) and +[Route](/configuration/route/#default_domain_resolver). + +For migration, +see [Migrate outbound DNS rule items to domain resolver](/migration/#migrate-outbound-dns-rule-items-to-domain-resolver). + +**3**: + +The new TLS fragment route options allow you to fragment TLS handshakes to bypass firewalls. + +This feature is intended to circumvent simple firewalls based on **plaintext packet matching**, and should not be used +to circumvent real censorship. + +Since it is not designed for performance, it should not be applied to all connections, but only to server names that are +known to be blocked. + +See [Route Action](/configuration/route/rule_action/#tls_fragment). + +**4**: + +New certificate options allow you to manage the default list of trusted X509 CA certificates. + +For the system certificate list, fixed Go not reading Android trusted certificates correctly. + +You can also use the Mozilla Included List instead, or add trusted certificates yourself. + +See [Certificate](/configuration/certificate/). + ### 1.11.0 Important changes since 1.10: From e9055b53e7abedcf3e760f87b905cddff81c1271 Mon Sep 17 00:00:00 2001 From: anytls <198425817+anytls@users.noreply.github.com> Date: Mon, 24 Feb 2025 10:40:12 +0800 Subject: [PATCH 62/62] Add MinIdleSession option to AnyTLS outbound Co-authored-by: anytls --- docs/configuration/outbound/anytls.md | 5 +++++ docs/configuration/outbound/anytls.zh.md | 5 +++++ go.mod | 2 +- go.sum | 6 ++---- option/anytls.go | 1 + protocol/anytls/outbound.go | 1 + 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/configuration/outbound/anytls.md b/docs/configuration/outbound/anytls.md index d5eb8fdf..4b3e0371 100644 --- a/docs/configuration/outbound/anytls.md +++ b/docs/configuration/outbound/anytls.md @@ -16,6 +16,7 @@ icon: material/new-box "password": "8JCsPssfgS8tiRwiMlhARg==", "idle_session_check_interval": "30s", "idle_session_timeout": "30s", + "min_idle_session": 5, "tls": {}, ... // Dial Fields @@ -50,6 +51,10 @@ Interval checking for idle sessions. Default: 30s. In the check, close sessions that have been idle for longer than this. Default: 30s. +#### min_idle_session + +In the check, at least the first `n` idle sessions are kept open. Default value: `n`=0 + #### tls ==Required== diff --git a/docs/configuration/outbound/anytls.zh.md b/docs/configuration/outbound/anytls.zh.md index 1d0828b1..1c888cfd 100644 --- a/docs/configuration/outbound/anytls.zh.md +++ b/docs/configuration/outbound/anytls.zh.md @@ -16,6 +16,7 @@ icon: material/new-box "password": "8JCsPssfgS8tiRwiMlhARg==", "idle_session_check_interval": "30s", "idle_session_timeout": "30s", + "min_idle_session": 5, "tls": {}, ... // 拨号字段 @@ -50,6 +51,10 @@ AnyTLS 密码。 在检查中,关闭闲置时间超过此值的会话。默认值:30秒。 +#### min_idle_session + +在检查中,至少前 `n` 个空闲会话保持打开状态。默认值:`n`=0 + #### tls ==必填== diff --git a/go.mod b/go.mod index bf45b4d6..01da2bb1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/sagernet/sing-box go 1.23.1 require ( - github.com/anytls/sing-anytls v0.0.2 + github.com/anytls/sing-anytls v0.0.3 github.com/caddyserver/certmagic v0.21.7 github.com/cloudflare/circl v1.6.0 github.com/cretz/bine v0.2.0 diff --git a/go.sum b/go.sum index a4638116..891e4766 100644 --- a/go.sum +++ b/go.sum @@ -8,10 +8,8 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/anytls/sing-anytls v0.0.1 h1:Hex6GFUcgATWMWL2E9YgH/7oPgwdokiIF09UQi5BEC0= -github.com/anytls/sing-anytls v0.0.1/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= -github.com/anytls/sing-anytls v0.0.2 h1:25azSh0o/LMcIkhS4ZutgRTIGwh8O3wuOhsThVM9K9o= -github.com/anytls/sing-anytls v0.0.2/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= +github.com/anytls/sing-anytls v0.0.3 h1:JAQpETCUiZ1LFAPnO8vyJsdxypvKB4zinXwy9KiqWeQ= +github.com/anytls/sing-anytls v0.0.3/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg= diff --git a/option/anytls.go b/option/anytls.go index 0ac19cd1..0f785263 100644 --- a/option/anytls.go +++ b/option/anytls.go @@ -21,4 +21,5 @@ type AnyTLSOutboundOptions struct { Password string `json:"password,omitempty"` IdleSessionCheckInterval badoption.Duration `json:"idle_session_check_interval,omitempty"` IdleSessionTimeout badoption.Duration `json:"idle_session_timeout,omitempty"` + MinIdleSession int `json:"min_idle_session,omitempty"` } diff --git a/protocol/anytls/outbound.go b/protocol/anytls/outbound.go index 3a016d2e..ce143bbe 100644 --- a/protocol/anytls/outbound.go +++ b/protocol/anytls/outbound.go @@ -63,6 +63,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL Password: options.Password, IdleSessionCheckInterval: options.IdleSessionCheckInterval.Build(), IdleSessionTimeout: options.IdleSessionTimeout.Build(), + MinIdleSession: options.MinIdleSession, DialOut: outbound.dialOut, Logger: logger, })