mirror of
https://github.com/DanielLavrushin/b4.git
synced 2026-08-15 12:03:49 +00:00
feat: add IP Health settings to manage unreachable address retest intervals
This commit is contained in:
parent
47bd723a0b
commit
7be08fbe76
13 changed files with 180 additions and 59 deletions
|
|
@ -22,6 +22,7 @@
|
|||
- CHANGED: **IP block detection also covers a destination that never answers its SYN** - the feature is described for addresses the firewall drops at the IP level, but it counted TLS ClientHello retransmissions, and a ClientHello exists only once a handshake has completed. An address-level block kills the handshake itself, so the single case the description named was the one case the check could not see, and what it did catch was a stateful block after the handshake.
|
||||
- ADDED: **The router tests a destination itself before treating it as blocked** - packets going unanswered for one device is equally consistent with a slow server, a brief routing glitch or an uplink outage, and acting on that alone resets connections to a destination nothing was ever wrong with. A dozen destinations failing within a minute reads as an uplink outage and suspends detection rather than condemning all of them.
|
||||
- FIXED: **A destination marked blocked stayed blocked for as long as anything kept trying it** - each lookup refreshed the entry's timestamp, so the five-minute expiry was never reached while a device kept retrying, and nothing re-tested the address in the meantime. A false positive, or a block that had since been lifted, held for the lifetime of the traffic.
|
||||
- ADDED: **An IP Health section in Settings** - how long a destination stays marked unreachable had no control of its own, and it belongs there rather than among a set's options, since whether an address answers depends on the address and the path to it rather than on the set that happened to match it.
|
||||
- ADDED: **A switch that strips unreachable addresses out of DNS answers** - a CDN answers with several addresses of which the firewall drops only some, so one device hangs on a blocked one while another on the same network loads the site. Pinning a working address by hand in the hosts file or as a `dnsmasq` alias had to be done per address, per domain, and again whenever the CDN changed its addresses.
|
||||
|
||||
## [1.74.2] - 2026-08-02
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
- ИЗМЕНЕНО: **Обнаружение блокировки по IP охватывает и адрес, который не отвечает на SYN** - функция описана для адресов, отбрасываемых файрволом на уровне IP, но считала повторы TLS ClientHello, а ClientHello появляется только после установленного рукопожатия. Блокировка по адресу убивает само рукопожатие, поэтому единственный случай, названный в описании, оказался тем самым, который проверка увидеть не могла, а ловила она блокировку с отслеживанием состояния уже после рукопожатия.
|
||||
- ДОБАВЛЕНО: **Роутер сам проверяет адрес, прежде чем считать его заблокированным** - отсутствие ответов у одного устройства одинаково хорошо объясняется медленным сервером, кратким сбоем маршрутизации или обрывом аплинка, и решение по одному этому признаку сбрасывало соединения к адресу, с которым всё было в порядке. Десяток адресов, отвалившихся за минуту, читается как обрыв аплинка и приостанавливает обнаружение, вместо того чтобы записать их все в заблокированные.
|
||||
- ИСПРАВЛЕНО: **Адрес, помеченный как заблокированный, оставался таким, пока к нему хоть что-то обращалось** - каждая проверка кэша обновляла отметку времени, поэтому пятиминутный срок не наступал, пока устройство продолжало попытки, и ничто не перепроверяло адрес. Ложное срабатывание или уже снятая блокировка держались столько же, сколько шёл трафик.
|
||||
- ДОБАВЛЕНО: **Раздел «Доступность IP» в настройках** - у срока, в течение которого адрес числится недоступным, не было собственной настройки, и место ей именно там, а не среди параметров сета: отвечает адрес или нет, зависит от самого адреса и пути к нему, а не от сета, который его поймал.
|
||||
- ДОБАВЛЕНО: **Переключатель, вырезающий недоступные адреса из DNS-ответов** - CDN отдаёт несколько адресов, из которых файрвол отбрасывает лишь часть, поэтому одно устройство зависает на заблокированном, пока другое в той же сети открывает сайт. Рабочий адрес приходилось прописывать вручную в hosts или через alias в `dnsmasq` - для каждого адреса, для каждого домена и заново при каждой смене адресов у CDN.
|
||||
|
||||
## [1.74.2] - 2026-08-02
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ var DefaultSetConfig = SetConfig{
|
|||
SynDetect: true,
|
||||
SynThreshold: DefaultIPBlockSynThreshold,
|
||||
HealDNS: false,
|
||||
BlockedTTLSec: DefaultIPBlockBlockedTTLSec,
|
||||
HealTTLSec: DefaultIPBlockHealTTLSec,
|
||||
},
|
||||
|
||||
|
|
@ -302,6 +301,10 @@ var DefaultConfig = Config{
|
|||
TCPDialSec: DefaultDNSTCPDialSec,
|
||||
},
|
||||
|
||||
IPHealth: IPHealthConfig{
|
||||
RetestIntervalSec: DefaultIPHealthRetestSec,
|
||||
},
|
||||
|
||||
Timezone: "",
|
||||
MemoryLimit: "",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ func TestIPBlockDetectResolvedDefaults(t *testing.T) {
|
|||
if got := zero.ResolvedSynThreshold(); got != DefaultIPBlockSynThreshold {
|
||||
t.Errorf("ResolvedSynThreshold = %d, want %d", got, DefaultIPBlockSynThreshold)
|
||||
}
|
||||
if got := zero.ResolvedBlockedTTL(); got != DefaultIPBlockBlockedTTLSec*time.Second {
|
||||
t.Errorf("ResolvedBlockedTTL = %s, want %ds", got, DefaultIPBlockBlockedTTLSec)
|
||||
}
|
||||
if got := zero.ResolvedHealTTL(); got != DefaultIPBlockHealTTLSec {
|
||||
t.Errorf("ResolvedHealTTL = %d, want %d", got, DefaultIPBlockHealTTLSec)
|
||||
}
|
||||
|
|
@ -55,7 +52,6 @@ func TestValidateIPBlockDetectFillsBlanks(t *testing.T) {
|
|||
set.Id = "s1"
|
||||
set.TCP.IPBlockDetect.Enabled = true
|
||||
set.TCP.IPBlockDetect.SynThreshold = 0
|
||||
set.TCP.IPBlockDetect.BlockedTTLSec = 0
|
||||
set.TCP.IPBlockDetect.HealTTLSec = 0
|
||||
cfg.Sets = []*SetConfig{&set}
|
||||
|
||||
|
|
@ -67,10 +63,78 @@ func TestValidateIPBlockDetectFillsBlanks(t *testing.T) {
|
|||
if ibd.SynThreshold != DefaultIPBlockSynThreshold {
|
||||
t.Errorf("syn_threshold = %d, want %d", ibd.SynThreshold, DefaultIPBlockSynThreshold)
|
||||
}
|
||||
if ibd.BlockedTTLSec != DefaultIPBlockBlockedTTLSec {
|
||||
t.Errorf("blocked_ttl_sec = %d, want %d", ibd.BlockedTTLSec, DefaultIPBlockBlockedTTLSec)
|
||||
}
|
||||
if ibd.HealTTLSec != DefaultIPBlockHealTTLSec {
|
||||
t.Errorf("heal_ttl_sec = %d, want %d", ibd.HealTTLSec, DefaultIPBlockHealTTLSec)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPHealthRetestIntervalIsGlobal(t *testing.T) {
|
||||
var zero IPHealthConfig
|
||||
if got := zero.RetestInterval(); got != DefaultIPHealthRetestSec*time.Second {
|
||||
t.Errorf("RetestInterval = %s, want %ds", got, DefaultIPHealthRetestSec)
|
||||
}
|
||||
|
||||
var nilCfg *IPHealthConfig
|
||||
if got := nilCfg.RetestInterval(); got != DefaultIPHealthRetestSec*time.Second {
|
||||
t.Errorf("nil RetestInterval = %s, want %ds", got, DefaultIPHealthRetestSec)
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.System.IPHealth.RetestIntervalSec = 0
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Fatalf("Validate: %v", err)
|
||||
}
|
||||
if cfg.System.IPHealth.RetestIntervalSec != DefaultIPHealthRetestSec {
|
||||
t.Errorf("retest_interval_sec = %d, want validation to fill the default", cfg.System.IPHealth.RetestIntervalSec)
|
||||
}
|
||||
|
||||
cfg.System.IPHealth.RetestIntervalSec = 90
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Fatalf("Validate: %v", err)
|
||||
}
|
||||
if got := cfg.System.IPHealth.RetestInterval(); got != 90*time.Second {
|
||||
t.Errorf("RetestInterval = %s, want an explicit 90s kept", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPHealthSparseRoundtrip(t *testing.T) {
|
||||
cfg := NewConfig()
|
||||
set := NewSetConfig()
|
||||
set.Id = "s1"
|
||||
cfg.Sets = []*SetConfig{&set}
|
||||
|
||||
data, err := MarshalSparse(&cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalSparse: %v", err)
|
||||
}
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if system, ok := raw["system"].(map[string]any); ok {
|
||||
if _, present := system["ip_health"]; present {
|
||||
t.Errorf("ip_health was written while it holds the default; the config file omits defaults")
|
||||
}
|
||||
}
|
||||
|
||||
cfg.System.IPHealth.RetestIntervalSec = 900
|
||||
data, err = MarshalSparse(&cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalSparse: %v", err)
|
||||
}
|
||||
raw = map[string]any{}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
system, ok := raw["system"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("system section missing")
|
||||
}
|
||||
ipHealth, ok := system["ip_health"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("ip_health missing after being set away from the default")
|
||||
}
|
||||
if got := ipHealth["retest_interval_sec"]; got != float64(900) {
|
||||
t.Errorf("retest_interval_sec = %v, want 900", got)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
DefaultIPBlockSynThreshold = 3
|
||||
DefaultIPBlockBlockedTTLSec = 300
|
||||
DefaultIPBlockHealTTLSec = 60
|
||||
DefaultIPBlockSynThreshold = 3
|
||||
DefaultIPBlockHealTTLSec = 60
|
||||
DefaultIPHealthRetestSec = 300
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -157,10 +157,20 @@ type IPBlockDetectConfig struct {
|
|||
SynDetect bool `json:"syn_detect"`
|
||||
SynThreshold int `json:"syn_threshold"`
|
||||
HealDNS bool `json:"heal_dns"`
|
||||
BlockedTTLSec int `json:"blocked_ttl_sec"`
|
||||
HealTTLSec int `json:"heal_ttl_sec"`
|
||||
}
|
||||
|
||||
type IPHealthConfig struct {
|
||||
RetestIntervalSec int `json:"retest_interval_sec"`
|
||||
}
|
||||
|
||||
func (c *IPHealthConfig) RetestInterval() time.Duration {
|
||||
if c == nil || c.RetestIntervalSec <= 0 {
|
||||
return DefaultIPHealthRetestSec * time.Second
|
||||
}
|
||||
return time.Duration(c.RetestIntervalSec) * time.Second
|
||||
}
|
||||
|
||||
func (c *IPBlockDetectConfig) ResolvedSynThreshold() int {
|
||||
if c == nil || c.SynThreshold <= 0 {
|
||||
return DefaultIPBlockSynThreshold
|
||||
|
|
@ -168,13 +178,6 @@ func (c *IPBlockDetectConfig) ResolvedSynThreshold() int {
|
|||
return c.SynThreshold
|
||||
}
|
||||
|
||||
func (c *IPBlockDetectConfig) ResolvedBlockedTTL() time.Duration {
|
||||
if c == nil || c.BlockedTTLSec <= 0 {
|
||||
return DefaultIPBlockBlockedTTLSec * time.Second
|
||||
}
|
||||
return time.Duration(c.BlockedTTLSec) * time.Second
|
||||
}
|
||||
|
||||
func (c *IPBlockDetectConfig) ResolvedHealTTL() uint32 {
|
||||
if c == nil || c.HealTTLSec <= 0 {
|
||||
return DefaultIPBlockHealTTLSec
|
||||
|
|
@ -302,6 +305,7 @@ type SystemConfig struct {
|
|||
API ApiConfig `json:"api"`
|
||||
AI AIConfig `json:"ai"`
|
||||
DNS DNSSystemConfig `json:"dns"`
|
||||
IPHealth IPHealthConfig `json:"ip_health"`
|
||||
Timezone string `json:"timezone"`
|
||||
MemoryLimit string `json:"memory_limit,omitempty"`
|
||||
Pprof bool `json:"pprof,omitempty"`
|
||||
|
|
|
|||
|
|
@ -119,14 +119,15 @@ func (c *Config) Validate() error {
|
|||
c.System.Logging.Directory = filepath.Clean(c.System.Logging.Directory)
|
||||
}
|
||||
|
||||
if c.System.IPHealth.RetestIntervalSec <= 0 {
|
||||
c.System.IPHealth.RetestIntervalSec = DefaultIPHealthRetestSec
|
||||
}
|
||||
|
||||
for setIdx, set := range c.Sets {
|
||||
ibd := &set.TCP.IPBlockDetect
|
||||
if ibd.SynThreshold <= 0 {
|
||||
ibd.SynThreshold = DefaultIPBlockSynThreshold
|
||||
}
|
||||
if ibd.BlockedTTLSec <= 0 {
|
||||
ibd.BlockedTTLSec = DefaultIPBlockBlockedTTLSec
|
||||
}
|
||||
if ibd.HealTTLSec <= 0 {
|
||||
ibd.HealTTLSec = DefaultIPBlockHealTTLSec
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ export const TcpGeneral = ({ config, queue, onChange }: TcpGeneralProps) => {
|
|||
syn_detect: true,
|
||||
syn_threshold: 3,
|
||||
heal_dns: false,
|
||||
blocked_ttl_sec: 300,
|
||||
heal_ttl_sec: 60,
|
||||
...config.tcp.ip_block_detect,
|
||||
};
|
||||
|
|
@ -242,22 +241,6 @@ export const TcpGeneral = ({ config, queue, onChange }: TcpGeneralProps) => {
|
|||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 6 }}>
|
||||
<B4Slider
|
||||
label={t("sets.tcp.general.ibdBlockedTtl")}
|
||||
value={ibd.blocked_ttl_sec}
|
||||
onChange={(value: number) =>
|
||||
onChange("tcp.ip_block_detect.blocked_ttl_sec", value)
|
||||
}
|
||||
min={60}
|
||||
max={3600}
|
||||
step={60}
|
||||
valueSuffix=" s"
|
||||
helperText={t("sets.tcp.general.ibdBlockedTtlHelper")}
|
||||
aiTopic="tcp.ip_block_detect.blocked_ttl_sec"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{ibd.heal_dns && (
|
||||
<Grid size={{ xs: 12, md: 6 }}>
|
||||
<B4Slider
|
||||
|
|
|
|||
50
src/http/ui/src/components/settings/IPHealth.tsx
Normal file
50
src/http/ui/src/components/settings/IPHealth.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { IpIcon } from "@b4.icons";
|
||||
import { B4FormGroup, B4Hint, B4NumberField, B4Section } from "@b4.elements";
|
||||
import { B4Config } from "@models/config";
|
||||
|
||||
interface IPHealthSettingsProps {
|
||||
config: B4Config;
|
||||
onChange: (
|
||||
field: string,
|
||||
value: number | boolean | string | string[],
|
||||
) => void;
|
||||
}
|
||||
|
||||
const DEFAULTS = {
|
||||
retest_interval_sec: 300,
|
||||
};
|
||||
|
||||
export const IPHealthSettings = ({
|
||||
config,
|
||||
onChange,
|
||||
}: IPHealthSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const ipHealth = { ...DEFAULTS, ...(config.system.ip_health ?? {}) };
|
||||
|
||||
return (
|
||||
<B4Section
|
||||
title={t("settings.IPHealth.title")}
|
||||
description={t("settings.IPHealth.description")}
|
||||
icon={<IpIcon />}
|
||||
>
|
||||
<B4Hint>{t("settings.IPHealth.info")}</B4Hint>
|
||||
|
||||
<B4FormGroup label={t("settings.IPHealth.group")} columns={2}>
|
||||
<B4NumberField
|
||||
label={t("settings.IPHealth.retestInterval")}
|
||||
value={ipHealth.retest_interval_sec}
|
||||
min={30}
|
||||
max={3600}
|
||||
onChange={(value) =>
|
||||
onChange("system.ip_health.retest_interval_sec", value)
|
||||
}
|
||||
helperText={t("settings.IPHealth.retestIntervalHelper")}
|
||||
aiTopic="system.ip_health.retest_interval_sec"
|
||||
/>
|
||||
</B4FormGroup>
|
||||
</B4Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default IPHealthSettings;
|
||||
|
|
@ -34,6 +34,7 @@ import { useSnackbar } from "@context/SnackbarProvider";
|
|||
import { useAiStatus } from "@context/AiStatusProvider";
|
||||
import { ApiSettings } from "./Api";
|
||||
import { DnsSettings } from "./Dns";
|
||||
import { IPHealthSettings } from "./IPHealth";
|
||||
import { CaptureSettings } from "./Capture";
|
||||
import { DevicesSettings } from "./Devices";
|
||||
import { CheckerSettings } from "./Discovery";
|
||||
|
|
@ -502,6 +503,12 @@ export function SettingsPage() {
|
|||
<DnsSettings config={config} onChange={handleChange} />
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 6 }} sx={{ display: "flex" }}>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<IPHealthSettings config={config} onChange={handleChange} />
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabPanel>
|
||||
|
||||
|
|
|
|||
|
|
@ -368,6 +368,14 @@
|
|||
"mssSizeHelp": "Lower values = more fragmentation. 88 is commonly used for YouTube bypass.",
|
||||
"info": "Reduces the TCP Maximum Segment Size on SYN/SYN-ACK packets for all TCP port 443 traffic, forcing data fragmentation. Most DPI systems cannot reassemble fragmented ClientHello. For per-device MSS clamping, use the Device Filtering settings."
|
||||
},
|
||||
"IPHealth": {
|
||||
"title": "IP Health",
|
||||
"description": "How long a destination stays marked unreachable",
|
||||
"info": "IP block detection is configured per set, but whether an address answers is a property of the address and the path to it, not of the set that matched it. The verdict is therefore shared across sets, and so is how long it lasts.",
|
||||
"group": "Retesting",
|
||||
"retestInterval": "Retest interval (seconds)",
|
||||
"retestIntervalHelper": "How long a destination stays marked unreachable before the router tests it again. Blocks get lifted and addresses get reassigned, so a verdict that never expires would strand devices on a stale one. This is also how long recovery takes, since a condemned address is reset before it can complete a handshake."
|
||||
},
|
||||
"Dns": {
|
||||
"title": "DNS",
|
||||
"description": "How b4 resolves DNS for matched sets, and how it handles DNS over TCP",
|
||||
|
|
@ -974,8 +982,6 @@
|
|||
"ibdThresholdWarn": "A low threshold may cause false positives - a single dropped packet or slow server could be mistaken for an IP block.",
|
||||
"ibdTimeout": "Detection Timeout",
|
||||
"ibdTimeoutHelper": "Alternative trigger: time since first attempt with no response",
|
||||
"ibdBlockedTtl": "Retest Interval",
|
||||
"ibdBlockedTtlHelper": "How long a destination stays marked blocked before it is tested again. Blocks get lifted and addresses get reassigned, so a verdict that never expires would strand devices on a stale one.",
|
||||
"ibdHealTtl": "Healed Answer TTL",
|
||||
"ibdHealTtlHelper": "TTL written into curated DNS answers. Keep it short so a device picks up a recovered address quickly instead of caching the curated answer for hours.",
|
||||
"ibdCache": "Cache Blocked IPs",
|
||||
|
|
|
|||
|
|
@ -364,6 +364,14 @@
|
|||
"mssSizeHelp": "Меньше значение = больше фрагментация. 88 часто используется для обхода YouTube.",
|
||||
"info": "Уменьшает TCP Maximum Segment Size на SYN/SYN-ACK пакетах для всего TCP трафика на порт 443, вызывая фрагментацию данных. Большинство DPI систем не могут пересобрать фрагментированный ClientHello. Для MSS clamping на отдельных устройствах используйте настройки фильтрации устройств."
|
||||
},
|
||||
"IPHealth": {
|
||||
"title": "Доступность IP",
|
||||
"description": "Сколько адрес числится недоступным",
|
||||
"info": "Обнаружение блокировки по IP настраивается для каждого сета, но отвечает адрес или нет - это свойство самого адреса и пути к нему, а не сета, который его поймал. Поэтому вердикт общий для всех сетов, и срок его жизни тоже.",
|
||||
"group": "Перепроверка",
|
||||
"retestInterval": "Интервал перепроверки (секунды)",
|
||||
"retestIntervalHelper": "Сколько адрес числится недоступным до следующей проверки роутером. Блокировки снимают, а адреса переиспользуют, поэтому бессрочный вердикт оставил бы устройства на устаревшем адресе. Столько же занимает и восстановление: соединение к отбракованному адресу сбрасывается раньше, чем успевает пройти рукопожатие."
|
||||
},
|
||||
"Dns": {
|
||||
"title": "DNS",
|
||||
"description": "Как b4 разрешает DNS для совпавших сетов и как обрабатывает DNS поверх TCP",
|
||||
|
|
@ -971,8 +979,6 @@
|
|||
"ibdThresholdWarn": "Низкий порог может вызвать ложные срабатывания - один потерянный пакет или медленный сервер могут быть приняты за блокировку IP.",
|
||||
"ibdTimeout": "Таймаут обнаружения",
|
||||
"ibdTimeoutHelper": "Альтернативный триггер: время с первой попытки без ответа",
|
||||
"ibdBlockedTtl": "Интервал перепроверки",
|
||||
"ibdBlockedTtlHelper": "Сколько адрес числится заблокированным до следующей проверки. Блокировки снимают, а адреса переиспользуют, поэтому бессрочный вердикт оставил бы устройства на устаревшем адресе.",
|
||||
"ibdHealTtl": "TTL исправленного ответа",
|
||||
"ibdHealTtlHelper": "TTL, который записывается в исправленные DNS-ответы. Держите его небольшим, чтобы устройство быстро подхватило восстановившийся адрес, а не кэшировало исправленный ответ часами.",
|
||||
"ibdCache": "Кэшировать заблокированные IP",
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ export interface SystemConfig {
|
|||
api: ApiConfig;
|
||||
ai: AIConfig;
|
||||
dns: DnsSystemConfig;
|
||||
ip_health?: IPHealthConfig;
|
||||
timezone: string;
|
||||
memory_limit?: string;
|
||||
}
|
||||
|
|
@ -458,6 +459,10 @@ export interface DuplicateConfig {
|
|||
count: number;
|
||||
}
|
||||
|
||||
export interface IPHealthConfig {
|
||||
retest_interval_sec: number;
|
||||
}
|
||||
|
||||
export interface IPBlockDetectConfig {
|
||||
enabled: boolean;
|
||||
retransmit_threshold: number;
|
||||
|
|
@ -466,7 +471,6 @@ export interface IPBlockDetectConfig {
|
|||
syn_detect: boolean;
|
||||
syn_threshold: number;
|
||||
heal_dns: boolean;
|
||||
blocked_ttl_sec: number;
|
||||
heal_ttl_sec: number;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,12 +109,12 @@ func NewPool(cfg *config.Config) *Pool {
|
|||
for {
|
||||
select {
|
||||
case <-cleanupTicker.C:
|
||||
blockedTTL := pool.blockedCacheTTL()
|
||||
retest := pool.retestInterval()
|
||||
pool.state.connState.Cleanup()
|
||||
pool.state.tlsCache.Cleanup()
|
||||
pool.state.destState.Cleanup(blockedTTL)
|
||||
pool.state.destState.Cleanup(retest)
|
||||
pool.state.hostHints.Cleanup()
|
||||
pool.state.ipHealth.Cleanup(blockedTTL)
|
||||
pool.state.ipHealth.Cleanup(retest)
|
||||
pool.state.goodIPs.Cleanup()
|
||||
case <-escalationTicker.C:
|
||||
pool.state.pendingHello.Cleanup()
|
||||
|
|
@ -335,21 +335,12 @@ func (p *Pool) GetIPBlockCache() IPBlockCache {
|
|||
return p.state.destState
|
||||
}
|
||||
|
||||
func (p *Pool) blockedCacheTTL() time.Duration {
|
||||
ttl := time.Duration(config.DefaultIPBlockBlockedTTLSec) * time.Second
|
||||
func (p *Pool) retestInterval() time.Duration {
|
||||
cfg := p.GetFirstWorkerConfig()
|
||||
if cfg == nil {
|
||||
return ttl
|
||||
return config.DefaultIPHealthRetestSec * time.Second
|
||||
}
|
||||
for _, set := range cfg.Sets {
|
||||
if set == nil || !set.TCP.IPBlockDetect.Enabled {
|
||||
continue
|
||||
}
|
||||
if d := set.TCP.IPBlockDetect.ResolvedBlockedTTL(); d > ttl {
|
||||
ttl = d
|
||||
}
|
||||
}
|
||||
return ttl
|
||||
return cfg.System.IPHealth.RetestInterval()
|
||||
}
|
||||
|
||||
func (p *Pool) GetEscalations() []metrics.EscalationEntry {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue