all: http api

This commit is contained in:
Stanislav Chzhen 2025-07-16 22:16:37 +03:00
parent fe49206905
commit 1ec3ec24ae
11 changed files with 89 additions and 11 deletions

View File

@ -22,6 +22,12 @@ NOTE: Add new changes BELOW THIS COMMENT.
- Go version has been updated to prevent the possibility of exploiting the Go vulnerabilities fixed in [1.24.5][go-1.24.5].
### Added
- Ability to enable or disable the global DNS response cache from the Web UI.
- A new `"cache_enabled"` field to the HTTP API (`GET /control/dns_info` and `POST /control/dns_config`). See `openapi/openapi.yaml` for the full description.
### Changed
#### Configuration changes

View File

@ -655,7 +655,10 @@
"safe_search": "Safe Search",
"blocklist": "Blocklist",
"milliseconds_abbreviation": "ms",
"cache_enabled": "Enable cache",
"cache_enabled_desc": "Store DNS responses locally.",
"cache_size": "Cache size",
"cache_size_validation": "Cache size must be greater than zero when cache is enabled.",
"cache_size_desc": "DNS cache size (in bytes). To disable caching, set to 0.",
"cache_ttl_min_override": "Override minimum TTL",
"cache_ttl_max_override": "Override maximum TTL",

View File

@ -32,6 +32,7 @@ const INPUTS_FIELDS = [
];
type FormData = {
cache_enabled: boolean;
cache_size: number;
cache_ttl_min: number;
cache_ttl_max: number;
@ -58,6 +59,7 @@ const Form = ({ initialValues, onSubmit }: CacheFormProps) => {
} = useForm<FormData>({
mode: 'onBlur',
defaultValues: {
cache_enabled: initialValues?.cache_enabled || false,
cache_size: initialValues?.cache_size || 0,
cache_ttl_min: initialValues?.cache_ttl_min || 0,
cache_ttl_max: initialValues?.cache_ttl_max || 0,
@ -65,10 +67,13 @@ const Form = ({ initialValues, onSubmit }: CacheFormProps) => {
},
});
const cache_enabled = watch('cache_enabled');
const cache_size = watch('cache_size');
const cache_ttl_min = watch('cache_ttl_min');
const cache_ttl_max = watch('cache_ttl_max');
const minExceedsMax = cache_ttl_min > 0 && cache_ttl_max > 0 && cache_ttl_min > cache_ttl_max;
const cacheSizeZeroWhenEnabled = cache_enabled && cache_size === 0;
const handleClearCache = () => {
if (window.confirm(t('confirm_dns_cache_clear'))) {
@ -79,6 +84,24 @@ const Form = ({ initialValues, onSubmit }: CacheFormProps) => {
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="row">
<div className="col-12 col-md-7">
<div className="form__group form__group--settings">
<Controller
name="cache_enabled"
control={control}
render={({ field }) => (
<Checkbox
{...field}
data-testid="dns_cache_enabled"
title={t('cache_enabled')}
subtitle={t('cache_enabled_desc')}
disabled={processingSetConfig}
/>
)}
/>
</div>
</div>
{INPUTS_FIELDS.map(({ name, title, description, placeholder }) => (
<div className="col-12" key={name}>
<div className="col-12 col-md-7 p-0">
@ -106,6 +129,7 @@ const Form = ({ initialValues, onSubmit }: CacheFormProps) => {
</div>
</div>
))}
{cacheSizeZeroWhenEnabled && <span className="text-danger pl-3 pb-3">{t('cache_size_validation')}</span>}
{minExceedsMax && <span className="text-danger pl-3 pb-3">{t('ttl_cache_validation')}</span>}
</div>
@ -133,7 +157,7 @@ const Form = ({ initialValues, onSubmit }: CacheFormProps) => {
type="submit"
data-testid="dns_save"
className="btn btn-success btn-standard btn-large"
disabled={isSubmitting || !isDirty || processingSetConfig || minExceedsMax}>
disabled={isSubmitting || !isDirty || processingSetConfig || minExceedsMax || cacheSizeZeroWhenEnabled}>
{t('save_btn')}
</button>

View File

@ -13,7 +13,7 @@ import { RootState } from '../../../../initialState';
const CacheConfig = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const { cache_size, cache_ttl_max, cache_ttl_min, cache_optimistic } = useSelector(
const { cache_enabled, cache_size, cache_ttl_max, cache_ttl_min, cache_optimistic } = useSelector(
(state: RootState) => state.dnsConfig,
shallowEqual,
);
@ -32,6 +32,7 @@ const CacheConfig = () => {
<div className="form">
<Form
initialValues={{
cache_enabled,
cache_size: replaceZeroWithEmptyString(cache_size),
cache_ttl_max: replaceZeroWithEmptyString(cache_ttl_max),
cache_ttl_min: replaceZeroWithEmptyString(cache_ttl_min),

View File

@ -322,6 +322,7 @@ export type DnsConfigData = {
ratelimit_subnet_len_ipv6?: number;
edns_cs_use_custom?: boolean;
edns_cs_custom_ip?: string;
cache_enabled?: boolean;
cache_size?: number;
cache_ttl_max?: number;
cache_ttl_min?: number;

View File

@ -27,11 +27,7 @@ func (m Migrator) migrateTo30(diskConf yobj) (err error) {
return err
}
if cacheSize > 0 {
dnsConf["cache_enabled"] = true
} else {
dnsConf["cache_enabled"] = false
}
dnsConf["cache_enabled"] = cacheSize > 0
return nil
}

View File

@ -93,6 +93,9 @@ type jsonDNSConfig struct {
// CacheMaxTTL is custom maximum TTL for cached DNS responses.
CacheMaxTTL *uint32 `json:"cache_ttl_max"`
// CacheEnabled defines if the DNS cache should be used.
CacheEnabled *bool `json:"cache_enabled"`
// CacheOptimistic defines if expired entries should be served.
CacheOptimistic *bool `json:"cache_optimistic"`
@ -162,6 +165,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
enableDNSSEC := s.conf.EnableDNSSEC
aaaaDisabled := s.conf.AAAADisabled
cacheEnabled := s.conf.CacheEnabled
cacheSize := s.conf.CacheSize
cacheMinTTL := s.conf.CacheMinTTL
cacheMaxTTL := s.conf.CacheMaxTTL
@ -207,6 +211,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
DNSSECEnabled: &enableDNSSEC,
DisableIPv6: &aaaaDisabled,
BlockedResponseTTL: &blockedResponseTTL,
CacheEnabled: &cacheEnabled,
CacheSize: &cacheSize,
CacheMinTTL: &cacheMinTTL,
CacheMaxTTL: &cacheMaxTTL,
@ -305,7 +310,7 @@ func (req *jsonDNSConfig) validate(
return err
}
err = req.checkCacheTTL()
err = req.checkCacheSettings()
if err != nil {
// Don't wrap the error since it's informative enough as is.
return err
@ -421,9 +426,14 @@ func (req *jsonDNSConfig) validateUpstreamDNSServers(
return nil
}
// checkCacheTTL returns an error if the configuration of the cache TTL is
// invalid.
func (req *jsonDNSConfig) checkCacheTTL() (err error) {
// checkCacheSettings returns an error if the cache configuration is invalid.
func (req *jsonDNSConfig) checkCacheSettings() (err error) {
if req.CacheEnabled != nil && *req.CacheEnabled {
if req.CacheSize == nil || *req.CacheSize == 0 {
return errors.Error("cache_size must be greater than 0 when cache_enabled is true")
}
}
if req.CacheMinTTL == nil && req.CacheMaxTTL == nil {
return nil
}
@ -596,6 +606,7 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
setIfNotNil(&s.conf.FallbackDNS, dc.Fallbacks),
setIfNotNil(&s.conf.EDNSClientSubnet.Enabled, dc.EDNSCSEnabled),
setIfNotNil(&s.conf.EDNSClientSubnet.UseCustom, dc.EDNSCSUseCustom),
setIfNotNil(&s.conf.CacheEnabled, dc.CacheEnabled),
setIfNotNil(&s.conf.CacheSize, dc.CacheSize),
setIfNotNil(&s.conf.CacheMinTTL, dc.CacheMinTTL),
setIfNotNil(&s.conf.CacheMaxTTL, dc.CacheMaxTTL),

View File

@ -32,6 +32,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -72,6 +73,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -112,6 +114,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,

View File

@ -37,6 +37,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -79,6 +80,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -122,6 +124,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -165,6 +168,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -208,6 +212,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -253,6 +258,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -299,6 +305,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -342,6 +349,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -387,6 +395,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -432,6 +441,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -475,6 +485,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -518,6 +529,7 @@
"cache_size": 1024,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -561,6 +573,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -604,6 +617,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -649,6 +663,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -694,6 +709,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -738,6 +754,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -781,6 +798,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -826,6 +844,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -874,6 +893,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -917,6 +937,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -964,6 +985,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -1007,6 +1029,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -1053,6 +1076,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,
@ -1096,6 +1120,7 @@
"cache_size": 0,
"cache_ttl_min": 0,
"cache_ttl_max": 0,
"cache_enabled": false,
"cache_optimistic": false,
"resolve_clients": false,
"use_private_ptr_resolvers": false,

View File

@ -4,6 +4,10 @@
## v0.108.0: API changes
## v0.107.64: API changes
- The new field `"cache_enabled"` in `GET /control/dns_info` and `POST /control/dns_config` enables or disables the DNS response cache.
## v0.107.58: API changes
### The ability to check rules for query types and/or clients: GET /control/check_host

View File

@ -1559,6 +1559,10 @@
'type': 'integer'
'cache_ttl_max':
'type': 'integer'
'cache_enabled':
'type': 'boolean'
'description': |
Enables or disables the DNS response cache.
'cache_optimistic':
'type': 'boolean'
'upstream_mode':