Pull request 2009: 4569-blocked-response-ttl

Updates #4569.

Squashed commit of the following:

commit cc5842fd9d19e6d8bc19f9f88a587c2dd102828d
Merge: 2e1e59e1b 5c6b3ace4
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Sep 13 13:41:59 2023 +0300

    Merge branch 'master' into 4569-blocked-response-ttl

commit 2e1e59e1b787d461819d01a99ceb70d21e882dc1
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Sep 12 20:28:34 2023 +0300

    client: fix input length

commit 05bfa8cff7bff020a5b655779513612bc353267f
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Sep 12 12:16:35 2023 +0300

    openapi: bump version

commit f4f36111265aea8927b9a5154d74954ba05e5f10
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 11 19:36:38 2023 +0300

    all: upg chlog

commit 09c1e6d75ee7a95a5286aed526521a0206026986
Merge: ff3e2dc9f fb332dfc2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 11 19:35:30 2023 +0300

    Merge branch 'master' into 4569-blocked-response-ttl

commit ff3e2dc9f1ed1aacf023821160c6973ee98506b7
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 11 19:34:59 2023 +0300

    client: add blocked response ttl

commit 31064d160e361f9e88f545fa42d8eb824ecc5c86
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Sep 11 15:58:06 2023 +0300

    all: add blocked response ttl
This commit is contained in:
Stanislav Chzhen 2023-09-13 13:58:12 +03:00
parent 5c6b3ace4a
commit a59fca2da3
12 changed files with 150 additions and 17 deletions

View File

@ -23,6 +23,13 @@ See also the [v0.107.39 GitHub milestone][ms-v0.107.39].
NOTE: Add new changes BELOW THIS COMMENT. NOTE: Add new changes BELOW THIS COMMENT.
--> -->
### Added
- Ability to specify for how long clients should cache a filtered response,
using the *Blocked response TTL* field on the *DNS settings* page ([#4569]).
[#4569]: https://github.com/AdguardTeam/AdGuardHome/issues/4569
<!-- <!--
NOTE: Add new changes ABOVE THIS COMMENT. NOTE: Add new changes ABOVE THIS COMMENT.
--> -->

View File

@ -283,6 +283,9 @@
"custom_ip": "Custom IP", "custom_ip": "Custom IP",
"blocking_ipv4": "Blocking IPv4", "blocking_ipv4": "Blocking IPv4",
"blocking_ipv6": "Blocking IPv6", "blocking_ipv6": "Blocking IPv6",
"blocked_response_ttl": "Blocked response TTL",
"blocked_response_ttl_desc": "Specifies for how many seconds the clients should cache a filtered response",
"form_enter_blocked_response_ttl": "Enter blocked response TTL (seconds)",
"dnscrypt": "DNSCrypt", "dnscrypt": "DNSCrypt",
"dns_over_https": "DNS-over-HTTPS", "dns_over_https": "DNS-over-HTTPS",
"dns_over_tls": "DNS-over-TLS", "dns_over_tls": "DNS-over-TLS",

View File

@ -68,10 +68,10 @@ const Form = ({
return <form onSubmit={handleSubmit}> return <form onSubmit={handleSubmit}>
<div className="row"> <div className="row">
<div className="col-12 col-sm-6"> <div className="col-12 col-md-7">
<div className="form__group form__group--settings"> <div className="form__group form__group--settings">
<label htmlFor="ratelimit" <label htmlFor="ratelimit"
className="form__label form__label--with-desc"> className="form__label form__label--with-desc">
<Trans>rate_limit</Trans> <Trans>rate_limit</Trans>
</label> </label>
<div className="form__desc form__desc--top"> <div className="form__desc form__desc--top">
@ -160,24 +160,46 @@ const Form = ({
name, name,
validateIp, validateIp,
}) => <div className="col-12 col-sm-6" key={name}> }) => <div className="col-12 col-sm-6" key={name}>
<div className="form__group form__group--settings"> <div className="form__group form__group--settings">
<label className="form__label form__label--with-desc" <label className="form__label form__label--with-desc"
htmlFor={name}><Trans>{name}</Trans> htmlFor={name}><Trans>{name}</Trans>
</label> </label>
<div className="form__desc form__desc--top"> <div className="form__desc form__desc--top">
<Trans>{description}</Trans> <Trans>{description}</Trans>
</div>
<Field
name={name}
component={renderInputField}
className="form-control"
placeholder={t('form_enter_ip')}
validate={[validateIp, validateRequiredValue]}
/>
</div> </div>
<Field </div>)}
name={name}
component={renderInputField}
className="form-control"
placeholder={t('form_enter_ip')}
validate={[validateIp, validateRequiredValue]}
/>
</div>
</div>)}
</> </>
)} )}
<div className="col-12 col-md-7">
<div className="form__group form__group--settings">
<label htmlFor="blocked_response_ttl"
className="form__label form__label--with-desc">
<Trans>blocked_response_ttl</Trans>
</label>
<div className="form__desc form__desc--top">
<Trans>blocked_response_ttl_desc</Trans>
</div>
<Field
name="blocked_response_ttl"
type="number"
component={renderInputField}
className="form-control"
placeholder={t('form_enter_blocked_response_ttl')}
normalize={toNumber}
validate={validateRequiredValue}
min={UINT32_RANGE.MIN}
max={UINT32_RANGE.MAX}
/>
</div>
</div>
</div> </div>
<button <button
type="submit" type="submit"

View File

@ -13,6 +13,7 @@ const Config = () => {
ratelimit, ratelimit,
blocking_ipv4, blocking_ipv4,
blocking_ipv6, blocking_ipv6,
blocked_response_ttl,
edns_cs_enabled, edns_cs_enabled,
edns_cs_use_custom, edns_cs_use_custom,
edns_cs_custom_ip, edns_cs_custom_ip,
@ -38,6 +39,7 @@ const Config = () => {
blocking_mode, blocking_mode,
blocking_ipv4, blocking_ipv4,
blocking_ipv6, blocking_ipv6,
blocked_response_ttl,
edns_cs_enabled, edns_cs_enabled,
disable_ipv6, disable_ipv6,
dnssec_enabled, dnssec_enabled,

View File

@ -49,6 +49,7 @@ const dnsConfig = handleActions(
ratelimit: 20, ratelimit: 20,
blocking_ipv4: DEFAULT_BLOCKING_IPV4, blocking_ipv4: DEFAULT_BLOCKING_IPV4,
blocking_ipv6: DEFAULT_BLOCKING_IPV6, blocking_ipv6: DEFAULT_BLOCKING_IPV6,
blocked_response_ttl: 10,
edns_cs_enabled: false, edns_cs_enabled: false,
disable_ipv6: false, disable_ipv6: false,
dnssec_enabled: false, dnssec_enabled: false,

View File

@ -65,6 +65,9 @@ type jsonDNSConfig struct {
// UpstreamMode defines the way DNS requests are constructed. // UpstreamMode defines the way DNS requests are constructed.
UpstreamMode *string `json:"upstream_mode"` UpstreamMode *string `json:"upstream_mode"`
// BlockedResponseTTL is the TTL for blocked responses.
BlockedResponseTTL *uint32 `json:"blocked_response_ttl"`
// CacheSize in bytes. // CacheSize in bytes.
CacheSize *uint32 `json:"cache_size"` CacheSize *uint32 `json:"cache_size"`
@ -115,6 +118,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
bootstraps := stringutil.CloneSliceOrEmpty(s.conf.BootstrapDNS) bootstraps := stringutil.CloneSliceOrEmpty(s.conf.BootstrapDNS)
fallbacks := stringutil.CloneSliceOrEmpty(s.conf.FallbackDNS) fallbacks := stringutil.CloneSliceOrEmpty(s.conf.FallbackDNS)
blockingMode, blockingIPv4, blockingIPv6 := s.dnsFilter.BlockingMode() blockingMode, blockingIPv4, blockingIPv6 := s.dnsFilter.BlockingMode()
blockedResponseTTL := s.dnsFilter.BlockedResponseTTL()
ratelimit := s.conf.Ratelimit ratelimit := s.conf.Ratelimit
customIP := s.conf.EDNSClientSubnet.CustomIP customIP := s.conf.EDNSClientSubnet.CustomIP
@ -158,6 +162,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
EDNSCSUseCustom: &useCustom, EDNSCSUseCustom: &useCustom,
DNSSECEnabled: &enableDNSSEC, DNSSECEnabled: &enableDNSSEC,
DisableIPv6: &aaaaDisabled, DisableIPv6: &aaaaDisabled,
BlockedResponseTTL: &blockedResponseTTL,
CacheSize: &cacheSize, CacheSize: &cacheSize,
CacheMinTTL: &cacheMinTTL, CacheMinTTL: &cacheMinTTL,
CacheMaxTTL: &cacheMaxTTL, CacheMaxTTL: &cacheMaxTTL,
@ -321,6 +326,10 @@ func (s *Server) setConfig(dc *jsonDNSConfig) (shouldRestart bool) {
s.dnsFilter.SetBlockingMode(*dc.BlockingMode, dc.BlockingIPv4, dc.BlockingIPv6) s.dnsFilter.SetBlockingMode(*dc.BlockingMode, dc.BlockingIPv4, dc.BlockingIPv6)
} }
if dc.BlockedResponseTTL != nil {
s.dnsFilter.SetBlockedResponseTTL(*dc.BlockedResponseTTL)
}
if dc.ProtectionEnabled != nil { if dc.ProtectionEnabled != nil {
s.dnsFilter.SetProtectionEnabled(*dc.ProtectionEnabled) s.dnsFilter.SetProtectionEnabled(*dc.ProtectionEnabled)
} }

View File

@ -60,6 +60,7 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) {
filterConf := &filtering.Config{ filterConf := &filtering.Config{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: filtering.BlockingModeDefault, BlockingMode: filtering.BlockingModeDefault,
BlockedResponseTTL: 10,
SafeBrowsingEnabled: true, SafeBrowsingEnabled: true,
SafeBrowsingCacheSize: 1000, SafeBrowsingCacheSize: 1000,
SafeSearchConf: filtering.SafeSearchConfig{Enabled: true}, SafeSearchConf: filtering.SafeSearchConfig{Enabled: true},
@ -137,6 +138,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
filterConf := &filtering.Config{ filterConf := &filtering.Config{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: filtering.BlockingModeDefault, BlockingMode: filtering.BlockingModeDefault,
BlockedResponseTTL: 10,
SafeBrowsingEnabled: true, SafeBrowsingEnabled: true,
SafeBrowsingCacheSize: 1000, SafeBrowsingCacheSize: 1000,
SafeSearchConf: filtering.SafeSearchConfig{Enabled: true}, SafeSearchConf: filtering.SafeSearchConfig{Enabled: true},
@ -229,6 +231,9 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
}, { }, {
name: "fallbacks", name: "fallbacks",
wantSet: "", wantSet: "",
}, {
name: "blocked_response_ttl",
wantSet: "",
}} }}
var data map[string]struct { var data map[string]struct {

View File

@ -20,6 +20,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -55,6 +56,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -90,6 +92,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,

View File

@ -25,6 +25,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -62,6 +63,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -100,6 +102,7 @@
"blocking_mode": "refused", "blocking_mode": "refused",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -138,6 +141,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -176,6 +180,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -214,6 +219,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": true, "edns_cs_enabled": true,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -254,6 +260,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": true, "edns_cs_enabled": true,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -294,6 +301,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -332,6 +340,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": true, "dnssec_enabled": true,
"disable_ipv6": false, "disable_ipv6": false,
@ -370,6 +379,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -408,6 +418,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -446,6 +457,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -486,6 +498,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -526,6 +539,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -565,6 +579,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -603,6 +618,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -643,6 +659,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -686,6 +703,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -724,6 +742,7 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,
@ -766,6 +785,46 @@
"blocking_mode": "default", "blocking_mode": "default",
"blocking_ipv4": "", "blocking_ipv4": "",
"blocking_ipv6": "", "blocking_ipv6": "",
"blocked_response_ttl": 10,
"edns_cs_enabled": false,
"dnssec_enabled": false,
"disable_ipv6": false,
"upstream_mode": "",
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
"local_ptr_upstreams": [],
"edns_cs_use_custom": false,
"edns_cs_custom_ip": ""
}
},
"blocked_response_ttl": {
"req": {
"blocked_response_ttl": 11
},
"want": {
"upstream_dns": [
"8.8.8.8:53",
"8.8.4.4:53"
],
"upstream_dns_file": "",
"bootstrap_dns": [
"9.9.9.10",
"149.112.112.10",
"2620:fe::10",
"2620:fe::fe:10"
],
"fallback_dns": [],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
"blocking_ipv6": "",
"blocked_response_ttl": 11,
"edns_cs_enabled": false, "edns_cs_enabled": false,
"dnssec_enabled": false, "dnssec_enabled": false,
"disable_ipv6": false, "disable_ipv6": false,

View File

@ -514,8 +514,19 @@ func (d *DNSFilter) BlockingMode() (mode BlockingMode, bIPv4, bIPv6 netip.Addr)
return d.conf.BlockingMode, d.conf.BlockingIPv4, d.conf.BlockingIPv6 return d.conf.BlockingMode, d.conf.BlockingIPv4, d.conf.BlockingIPv6
} }
// SetBlockedResponseTTL sets TTL for blocked responses.
func (d *DNSFilter) SetBlockedResponseTTL(ttl uint32) {
d.confMu.Lock()
defer d.confMu.Unlock()
d.conf.BlockedResponseTTL = ttl
}
// BlockedResponseTTL returns TTL for blocked responses. // BlockedResponseTTL returns TTL for blocked responses.
func (d *DNSFilter) BlockedResponseTTL() (ttl uint32) { func (d *DNSFilter) BlockedResponseTTL() (ttl uint32) {
d.confMu.Lock()
defer d.confMu.Unlock()
return d.conf.BlockedResponseTTL return d.conf.BlockedResponseTTL
} }

View File

@ -4,6 +4,13 @@
## v0.108.0: API changes ## v0.108.0: API changes
## v0.107.39: API changes
### The new field `"blocked_response_ttl"` in `DNSConfig` object
* The new field `"blocked_response_ttl"` in `GET /control/dns_info` and `POST
/control/dns_config` is the TTL for blocked responses.
## v0.107.37: API changes ## v0.107.37: API changes
### The new field `"fallback_dns"` in `UpstreamsConfig` object ### The new field `"fallback_dns"` in `UpstreamsConfig` object

View File

@ -1460,6 +1460,10 @@
'type': 'string' 'type': 'string'
'blocking_ipv6': 'blocking_ipv6':
'type': 'string' 'type': 'string'
'blocked_response_ttl':
'type': 'integer'
'minimum': 0
'description': 'TTL for blocked responses.'
'protection_disabled_until': 'protection_disabled_until':
'type': 'string' 'type': 'string'
'description': 'Protection is pause until this time. Nullable.' 'description': 'Protection is pause until this time. Nullable.'