|
|
|
@ -16,29 +16,30 @@ type Address struct { |
|
|
|
|
v6 bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type Endpoint struct { |
|
|
|
|
addr Address |
|
|
|
|
type EndpointState int |
|
|
|
|
|
|
|
|
|
loginPos SourcePos |
|
|
|
|
passwordPos SourcePos |
|
|
|
|
const ( |
|
|
|
|
ES_Normal EndpointState = iota |
|
|
|
|
ES_Delayed |
|
|
|
|
ES_Deleted |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
delayUntil time.Time |
|
|
|
|
// An Endpoint represents a remote target and stores its persistent data between multiple connections.
|
|
|
|
|
type Endpoint struct { |
|
|
|
|
addr Address // IP address of an endpoint
|
|
|
|
|
|
|
|
|
|
normalList *list.Element |
|
|
|
|
delayedList *list.Element |
|
|
|
|
loginPos, passwordPos SourcePos // login/password cursors
|
|
|
|
|
listElement *list.Element // position in list
|
|
|
|
|
|
|
|
|
|
goodConn int |
|
|
|
|
badConn int |
|
|
|
|
consecutiveGoodConn int |
|
|
|
|
consecutiveBadConn int |
|
|
|
|
protoErrors int |
|
|
|
|
consecutiveProtoErrors int |
|
|
|
|
readErrors int |
|
|
|
|
consecutiveReadErrors int |
|
|
|
|
state EndpointState // which state an endpoint is in
|
|
|
|
|
delayUntil time.Time // when this endpoint can be used again
|
|
|
|
|
|
|
|
|
|
mutex sync.Mutex |
|
|
|
|
// endpoint stats
|
|
|
|
|
goodConn, badConn, protoErrors, readErrors int |
|
|
|
|
consecutiveGoodConn, consecutiveBadConn, consecutiveProtoErrors, |
|
|
|
|
consecutiveReadErrors int |
|
|
|
|
|
|
|
|
|
deleted bool // set to TRUE to mark this endpoint as deleted
|
|
|
|
|
mutex sync.Mutex // sync primitive
|
|
|
|
|
|
|
|
|
|
// unused, for now
|
|
|
|
|
rtt float32 |
|
|
|
@ -48,12 +49,35 @@ type Endpoint struct { |
|
|
|
|
lastAttemptAt time.Time // same, but for attempts
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var endpoints *list.List // Contains all active endpoints
|
|
|
|
|
var delayedEndpoints *list.List // Contains endpoints that got delayed
|
|
|
|
|
var endpoints *list.List // Contains all active and ready endpoints
|
|
|
|
|
var delayedEndpoints *list.List // Contains endpoints that are active, but not ready
|
|
|
|
|
|
|
|
|
|
// A mutex for synchronizing Endpoint collections.
|
|
|
|
|
var globalEndpointMutex sync.Mutex |
|
|
|
|
|
|
|
|
|
func (state EndpointState) String() string { |
|
|
|
|
switch state { |
|
|
|
|
case ES_Normal: |
|
|
|
|
return "normal" |
|
|
|
|
case ES_Delayed: |
|
|
|
|
return "delayed" |
|
|
|
|
case ES_Deleted: |
|
|
|
|
return "deleted" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return "unknown" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (state EndpointState) GetList() *list.List { |
|
|
|
|
switch state { |
|
|
|
|
case ES_Normal: |
|
|
|
|
return endpoints |
|
|
|
|
case ES_Delayed: |
|
|
|
|
return delayedEndpoints |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// String transforms an Endpoint to a string representation compatible with Dialer interface.
|
|
|
|
|
func (e *Endpoint) String() string { |
|
|
|
@ -64,6 +88,9 @@ func (e *Endpoint) String() string { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (e *Endpoint) GetList() *list.List { |
|
|
|
|
return e.state.GetList() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Delete deletes an endpoint from global storage.
|
|
|
|
|
// This method assumes that Endpoint's mutex was already taken.
|
|
|
|
@ -71,51 +98,55 @@ func (e *Endpoint) Delete() { |
|
|
|
|
globalEndpointMutex.Lock() |
|
|
|
|
defer globalEndpointMutex.Unlock() |
|
|
|
|
|
|
|
|
|
e.delayUntil = time.Time{} |
|
|
|
|
|
|
|
|
|
if e.delayedList != nil { |
|
|
|
|
log("ep", 3, "deleting delayed endpoint \"%v\"", e) |
|
|
|
|
delayedEndpoints.Remove(e.delayedList) |
|
|
|
|
e.delayedList = nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if e.normalList != nil { |
|
|
|
|
list := e.GetList() |
|
|
|
|
if list != nil { |
|
|
|
|
log("ep", 3, "deleting endpoint \"%v\"", e) |
|
|
|
|
endpoints.Remove(e.normalList) |
|
|
|
|
e.normalList = nil |
|
|
|
|
list.Remove(e.listElement) |
|
|
|
|
e.listElement = nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
e.deleted = true |
|
|
|
|
e.delayUntil = time.Time{} |
|
|
|
|
e.state = ES_Deleted |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Delay marks an Endpoint as "delayed" with the specified time duration
|
|
|
|
|
// and causes it to move to the delayed queue.
|
|
|
|
|
// This method assumes that Endpoint's mutex was already taken.
|
|
|
|
|
func (e *Endpoint) Delay(addTime time.Duration) { |
|
|
|
|
if e.deleted { |
|
|
|
|
// SetState changes an endpoint's state.
|
|
|
|
|
func (e *Endpoint) SetState(newState EndpointState) { |
|
|
|
|
if e.state == newState { |
|
|
|
|
log("ep", 5, "ignoring state change for an endpoint \"%v\": already in state \"%v\"", e, e.state) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log("ep", 5, "delaying endpoint \"%v\" for %v", e, addTime) |
|
|
|
|
e.delayUntil = time.Now().Add(addTime) |
|
|
|
|
e.MigrateToDelayed() |
|
|
|
|
} |
|
|
|
|
oldList := e.GetList() |
|
|
|
|
newList := newState.GetList() |
|
|
|
|
|
|
|
|
|
// MigrateToDelayed moves an Endpoint to a delayed queue.
|
|
|
|
|
// Endpoint mutex is assumed to be taken.
|
|
|
|
|
func (e *Endpoint) MigrateToDelayed() { |
|
|
|
|
endpointMutex.Lock() |
|
|
|
|
defer endpointMutex.Unlock() |
|
|
|
|
globalEndpointMutex.Lock() |
|
|
|
|
defer globalEndpointMutex.Unlock() |
|
|
|
|
|
|
|
|
|
if e.delayedList != nil { |
|
|
|
|
// already in a delayed list
|
|
|
|
|
log("ep", 5, "cannot migrate endpoint \"%v\" to delayed list: already in the list", e) |
|
|
|
|
if e.listElement != nil { |
|
|
|
|
oldList.Remove(e.listElement) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if newList == nil { |
|
|
|
|
e.listElement = nil |
|
|
|
|
} else { |
|
|
|
|
log("ep", 5, "migrating endpoint \"%v\" to delayed list", e) |
|
|
|
|
e.delayedList = delayedEndpoints.PushBack(e) |
|
|
|
|
if e.normalList != nil { |
|
|
|
|
endpoints.Remove(e.normalList) |
|
|
|
|
e.normalList = nil |
|
|
|
|
e.listElement = newList.PushBack(e) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Delay marks an Endpoint as "delayed" for a certain duration
|
|
|
|
|
// and migrates it to the delayed queue.
|
|
|
|
|
// This method assumes that Endpoint's mutex was already taken.
|
|
|
|
|
func (e *Endpoint) Delay(addTime time.Duration) { |
|
|
|
|
if e.state == ES_Normal { |
|
|
|
|
log("ep", 5, "delaying endpoint \"%v\" for %v", e, addTime) |
|
|
|
|
e.delayUntil = time.Now().Add(addTime) |
|
|
|
|
e.SetState(ES_Delayed) |
|
|
|
|
} else if e.state == ES_Delayed { |
|
|
|
|
// endpoints that are already delayed can have their delay time extended further
|
|
|
|
|
|
|
|
|
|
tm := time.Now().Add(addTime) |
|
|
|
|
if e.delayUntil.Before(tm) { |
|
|
|
|
e.delayUntil = tm |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -170,30 +201,30 @@ func (e *Endpoint) NoResponse() bool { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 1. always bail after X consecutive bad conns
|
|
|
|
|
if e.consecutiveBadConn >= CfgGetInt("max-bad-conn") { |
|
|
|
|
if e.consecutiveBadConn >= getParamInt("max-bad-conn") { |
|
|
|
|
log("ep", 3, "deleting \"%v\" due to max-bad-conn", e) |
|
|
|
|
e.Delete() |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2. after a good conn, always allow at most X bad conns
|
|
|
|
|
if e.goodConn > 0 && e.consecutiveBadConn <= CfgGetInt("max-bad-after-good-conn") { |
|
|
|
|
if e.goodConn > 0 && e.consecutiveBadConn <= getParamInt("max-bad-after-good-conn") { |
|
|
|
|
log("ep", 3, "keeping \"%v\" around due to max-bad-after-good-conn", e) |
|
|
|
|
e.Delay(CfgGetDurationMS("no-response-delay-ms")) |
|
|
|
|
e.Delay(getParamDurationMS("no-response-delay-ms")) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 3. always allow at most X bad conns
|
|
|
|
|
if e.consecutiveBadConn < CfgGetInt("min-bad-conn") { |
|
|
|
|
if e.consecutiveBadConn < getParamInt("min-bad-conn") { |
|
|
|
|
log("ep", 3, "keeping \"%v\" around due to min-bad-conn", e) |
|
|
|
|
e.Delay(CfgGetDurationMS("no-response-delay-ms")) |
|
|
|
|
e.Delay(getParamDurationMS("no-response-delay-ms")) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 4. bad conn/good conn ratio must not be higher than X
|
|
|
|
|
if e.goodConn > 0 && (float64(e.badConn)/float64(e.goodConn)) <= CfgGetFloat("conn-ratio") { |
|
|
|
|
if e.goodConn > 0 && (float64(e.badConn)/float64(e.goodConn)) <= getParamFloat("conn-ratio") { |
|
|
|
|
log("ep", 3, "keeping \"%v\" around due to conn-ratio", e) |
|
|
|
|
e.Delay(CfgGetDurationMS("no-response-delay-ms")) |
|
|
|
|
e.Delay(getParamDurationMS("no-response-delay-ms")) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -213,23 +244,23 @@ func (e *Endpoint) ProtocolError() bool { |
|
|
|
|
e.consecutiveProtoErrors++ |
|
|
|
|
|
|
|
|
|
// 1. always bail after X consecutive protocol errors
|
|
|
|
|
if e.consecutiveProtoErrors >= CfgGetInt("max-proto-errors") { |
|
|
|
|
if e.consecutiveProtoErrors >= getParamInt("max-proto-errors") { |
|
|
|
|
log("ep", 3, "deleting \"%v\" due to max-proto-errors", e) |
|
|
|
|
e.Delete() |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2. always allow at most X consecutive protocol errors
|
|
|
|
|
if e.consecutiveProtoErrors < CfgGetInt("min-proto-errors") { |
|
|
|
|
if e.consecutiveProtoErrors < getParamInt("min-proto-errors") { |
|
|
|
|
log("ep", 3, "keeping \"%v\" around due to min-proto-errors", e) |
|
|
|
|
e.Delay(CfgGetDurationMS("protocol-error-delay-ms")) |
|
|
|
|
e.Delay(getParamDurationMS("protocol-error-delay-ms")) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 3. bad conn/good conn ratio must not be higher than X
|
|
|
|
|
if e.goodConn > 0 && (float64(e.protoErrors)/float64(e.goodConn)) <= CfgGetFloat("proto-error-ratio") { |
|
|
|
|
if e.goodConn > 0 && (float64(e.protoErrors)/float64(e.goodConn)) <= getParamFloat("proto-error-ratio") { |
|
|
|
|
log("ep", 3, "keeping \"%v\" around due to proto-error-ratio", e) |
|
|
|
|
e.Delay(CfgGetDurationMS("protocol-error-delay-ms")) |
|
|
|
|
e.Delay(getParamDurationMS("protocol-error-delay-ms")) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -257,7 +288,7 @@ func (e *Endpoint) Good(login) { |
|
|
|
|
defer e.mutex.Unlock() |
|
|
|
|
e.consecutiveProtoErrors = 0 |
|
|
|
|
|
|
|
|
|
if !CfgGetSwitch("keep-endpoint-on-good") { |
|
|
|
|
if !getParamSwitch("keep-endpoint-on-good") { |
|
|
|
|
e.Delete() |
|
|
|
|
} else { |
|
|
|
|
e.MigrateToNormal() |
|
|
|
@ -337,6 +368,7 @@ func (e *Endpoint) Exhausted() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GetDelayedEndpoint retrieves an Endpoint from the delayed list.
|
|
|
|
|
// globalEndpointMutex must be already taken.
|
|
|
|
|
func GetDelayedEndpoint() (e *Endpoint, waitTime time.Duration) { |
|
|
|
|
currentTime := time.Now() |
|
|
|
|
|
|
|
|
@ -350,7 +382,7 @@ func GetDelayedEndpoint() (e *Endpoint, waitTime time.Duration) { |
|
|
|
|
k, v := it.Key().(time.Time), it.Value().(*Endpoint) |
|
|
|
|
|
|
|
|
|
if v == nil { |
|
|
|
|
log("ep", 5, "!!! empty delayed endpoint!!!") |
|
|
|
|
panic("delayed endpoint list contains an empty endpoint") |
|
|
|
|
return nil, 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -381,13 +413,15 @@ func GetDelayedEndpoint() (e *Endpoint, waitTime time.Duration) { |
|
|
|
|
return nil, 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// FetchEndpoint retrieves an endpoint: first, a delayed RB tree is queried,
|
|
|
|
|
// FetchEndpoint retrieves an endpoint: first, a delayed list is queried,
|
|
|
|
|
// then, if nothing is found, a normal list is searched,
|
|
|
|
|
// and (TODO) if this list is empty or will soon be emptied,
|
|
|
|
|
// a new batch of endpoints gets created.
|
|
|
|
|
func FetchEndpoint() (e *Endpoint, waitTime time.Duration) { |
|
|
|
|
endpointMutex.Lock() |
|
|
|
|
defer endpointMutex.Unlock() |
|
|
|
|
globalEndpointMutex.Lock() |
|
|
|
|
defer globalEndpointMutex.Unlock() |
|
|
|
|
|
|
|
|
|
log("ep", 4, "fetching an endpoint") |
|
|
|
|
|
|
|
|
|
e, waitTime = GetDelayedEndpoint() |
|
|
|
|
if e != nil { |
|
|
|
@ -413,6 +447,10 @@ func FetchEndpoint() (e *Endpoint, waitTime time.Duration) { |
|
|
|
|
return e, 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ---
|
|
|
|
|
// ---
|
|
|
|
|
// ---
|
|
|
|
|
|
|
|
|
|
// Safety feature, to avoid expanding subnets into a huge amount of IPs.
|
|
|
|
|
const maxNetmaskSize = 22 // expands into /10 for IPv4
|
|
|
|
|
|
|
|
|
@ -424,7 +462,7 @@ func RegisterEndpoint(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
ep.passwordPos.Reset() |
|
|
|
|
|
|
|
|
|
ep.listElement = endpoints.PushBack(&ep) |
|
|
|
|
log("ep", 3, "ok registered: %v", &ep) |
|
|
|
|
log("ep", 3, "registered endpoint: %v", &ep) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return len(ports) |
|
|
|
@ -439,6 +477,7 @@ func incIP(ip net.IP) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// parseCIDR registers multiple endpoints from a CIDR netmask.
|
|
|
|
|
func parseCIDR(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
na, nm, err := net.ParseCIDR(ip) |
|
|
|
|
if err != nil { |
|
|
|
@ -455,7 +494,7 @@ func parseCIDR(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
curHost := 0 |
|
|
|
|
maxHost := 1<<(maskBits-mask) - 1 |
|
|
|
|
numParsed := 0 |
|
|
|
|
strict := CfgGetSwitch("strict-subnets") |
|
|
|
|
strict := getParamSwitch("strict-subnets") |
|
|
|
|
|
|
|
|
|
log("ep", 2, "expanding CIDR: \"%v\" to %v hosts", ip, maxHost+1) |
|
|
|
|
|
|
|
|
@ -463,7 +502,7 @@ func parseCIDR(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
if strict && (curHost == 0 || curHost == maxHost) && maskBits-mask >= 2 { |
|
|
|
|
log("ep", 1, "ignoring network/broadcast address due to strict-subnets: \"%v\"", expIP.String()) |
|
|
|
|
} else { |
|
|
|
|
numParsed += parseIPPorts(expIP.String(), ports, isIPv6) |
|
|
|
|
numParsed += RegisterEndpoint(expIP.String(), ports, isIPv6) |
|
|
|
|
} |
|
|
|
|
curHost++ |
|
|
|
|
} |
|
|
|
@ -471,7 +510,8 @@ func parseCIDR(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
return numParsed |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func parseIPPorts(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
// parseIPOrCIDR expands plain IP or CIDR to multiple endpoints.
|
|
|
|
|
func parseIPOrCIDR(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
// ip may be a domain name, a CIDR subnet or an IP address
|
|
|
|
|
// CIDR subnets must be expanded to plain IPs
|
|
|
|
|
|
|
|
|
@ -485,7 +525,8 @@ func parseIPPorts(ip string, ports []int, isIPv6 bool) int { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func extractIPAndPort(str string, skippedIPv6 *int) (ip string, port int, err error) { |
|
|
|
|
// extractIPAndPort extracts all endpoint components.
|
|
|
|
|
func extractIPAndPort(str string) (ip string, port int, err error) { |
|
|
|
|
var portString string |
|
|
|
|
ip, portString, err = net.SplitHostPort(str) |
|
|
|
|
if err != nil { |
|
|
|
@ -504,8 +545,10 @@ func extractIPAndPort(str string, skippedIPv6 *int) (ip string, port int, err er |
|
|
|
|
return ip, port, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ParseEndpoints takes a string slice of IPs/CIDR subnets and converts it to a list of endpoints.
|
|
|
|
|
func ParseEndpoints(source []string) { |
|
|
|
|
log("ep", 1, "parsing endpoints") |
|
|
|
|
|
|
|
|
|
totalIPv6Skipped := 0 |
|
|
|
|
numParsed := 0 |
|
|
|
|
|
|
|
|
@ -514,74 +557,72 @@ func ParseEndpoints(source []string) { |
|
|
|
|
// no ":": this is an ipv4/dn without port,
|
|
|
|
|
// parse it with all known ports
|
|
|
|
|
|
|
|
|
|
numParsed += parseIPPorts(str, CfgGetIntSlice("port"), false) |
|
|
|
|
numParsed += parseIPOrCIDR(str, getParamIntSlice("port"), false) |
|
|
|
|
} else { |
|
|
|
|
// either ipv4/dn with port, or ipv6 with/without port
|
|
|
|
|
|
|
|
|
|
isIPv6 := strings.Count(str, ":") > 1 |
|
|
|
|
if isIPv6 && CfgGetSwitch("no-ipv6") { |
|
|
|
|
log("ep", 1, "skipping ipv6 target \"%v\" due to no-ipv6", str) |
|
|
|
|
if isIPv6 && getParamSwitch("no-ipv6") { |
|
|
|
|
totalIPv6Skipped++ |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !strings.Contains(str, "]:") && strings.Contains(str, "::") { |
|
|
|
|
// ipv6 without port
|
|
|
|
|
numParsed += parseIPPorts(str, CfgGetIntSlice("port"), true) |
|
|
|
|
numParsed += parseIPOrCIDR(str, getParamIntSlice("port"), true) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ip, port, err := extractIPAndPort(str, &totalIPv6Skipped) |
|
|
|
|
ip, port, err := extractIPAndPort(str) |
|
|
|
|
if err != nil { |
|
|
|
|
log("ep", 0, "failed to extract ip/port for \"%v\": %v", str, err.Error()) |
|
|
|
|
log("ep", 0, "failed to extract ip/port for \"%v\": %v, ignoring endpoint", str, err.Error()) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ports := []int{port} |
|
|
|
|
// append all default ports
|
|
|
|
|
if CfgGetSwitch("append-default-ports") { |
|
|
|
|
for _, port2 := range CfgGetIntSlice("port") { |
|
|
|
|
if getParamSwitch("append-default-ports") { |
|
|
|
|
for _, port2 := range getParamIntSlice("port") { |
|
|
|
|
if port != port2 { |
|
|
|
|
ports = append(ports, port2) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
numParsed += parseIPPorts(ip, ports, isIPv6) |
|
|
|
|
numParsed += parseIPOrCIDR(ip, ports, isIPv6) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logIf(totalIPv6Skipped > 0, "ep", 0, "skipping %v IPv6 targets due to no-ipv6 flag", totalIPv6Skipped) |
|
|
|
|
log("ep", 1, "finished parsing endpoints: got %v, total %v", numParsed, endpoints.Len()) |
|
|
|
|
logIf(totalIPv6Skipped > 0, "ep", 0, "skipped %v IPv6 targets due to no-ipv6 flag", totalIPv6Skipped) |
|
|
|
|
log("ep", 1, "finished parsing endpoints: parsed %v out of total %v", numParsed, endpoints.Len()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func init() { |
|
|
|
|
endpoints = list.New() |
|
|
|
|
delayedEndpoints = list.New() |
|
|
|
|
|
|
|
|
|
CfgRegister("port", []int{8291}, "one or more default ports") |
|
|
|
|
CfgRegister("max-aps", 5, "maximum number of attempts per second for an endpoint") |
|
|
|
|
CfgRegisterSwitch("no-ipv6", "skip IPv6 entries") |
|
|
|
|
CfgRegisterSwitch("append-default-ports", "always append default ports even for targets in host:port format") |
|
|
|
|
CfgRegisterSwitch("strict-subnets", "strict subnet behaviour: ignore network and broadcast addresses in /30 and bigger subnets") |
|
|
|
|
|
|
|
|
|
CfgRegisterSwitch("keep-endpoint-on-good", "keep processing endpoint if a login/password was found") |
|
|
|
|
registerParam("port", []int{8291}, "one or more default ports") |
|
|
|
|
registerParam("max-aps", 5, "maximum number of attempts per second for an endpoint") |
|
|
|
|
registerSwitch("no-ipv6", "skip IPv6 entries") |
|
|
|
|
registerSwitch("append-default-ports", "always append default ports even for targets in host:port format") |
|
|
|
|
registerSwitch("strict-subnets", "strict subnet behaviour: ignore network and broadcast addresses in /30 and bigger subnets") |
|
|
|
|
|
|
|
|
|
CfgRegister("conn-ratio", 0.15, "keep a failed endpoint if its bad/good connection ratio is lower than this value") |
|
|
|
|
CfgRegister("max-bad-after-good-conn", 5, "how many consecutive bad connections to allow after a good connection") |
|
|
|
|
CfgRegister("max-bad-conn", 20, "always remove endpoint after this many consecutive bad connections") |
|
|
|
|
CfgRegister("min-bad-conn", 2, "do not consider removing an endpoint if it does not have this many consecutive bad connections") |
|
|
|
|
registerSwitch("keep-endpoint-on-good", "keep processing endpoint if a login/password was found") |
|
|
|
|
|
|
|
|
|
CfgRegister("proto-error-ratio", 0.25, "keep endpoints with a protocol error if their protocol error ratio is lower than this value") |
|
|
|
|
CfgRegister("max-proto-errors", 20, "always remove endpoint after this many consecutive protocol errors") |
|
|
|
|
CfgRegister("min-proto-errors", 4, "do not consider removing an endpoint if it does not have this many consecutive protocol errors") |
|
|
|
|
registerParam("conn-ratio", 0.15, "keep a failed endpoint if its bad/good connection ratio is lower than this value") |
|
|
|
|
registerParam("max-bad-after-good-conn", 5, "how many consecutive bad connections to allow after a good connection") |
|
|
|
|
registerParam("max-bad-conn", 20, "always remove endpoint after this many consecutive bad connections") |
|
|
|
|
registerParam("min-bad-conn", 2, "do not consider removing an endpoint if it does not have this many consecutive bad connections") |
|
|
|
|
|
|
|
|
|
CfgRegister("read-error-ratio", 0.25, "keep endpoints with a read error if their read error ratio is lower than this value") |
|
|
|
|
CfgRegister("max-read-errors", 20, "always remove endpoint after this many consecutive read errors") |
|
|
|
|
CfgRegister("min-read-errors", 3, "do not consider removing an endpoint if it does not have this many consecutive read errors") |
|
|
|
|
registerParam("proto-error-ratio", 0.25, "keep endpoints with a protocol error if their protocol error ratio is lower than this value") |
|
|
|
|
registerParam("max-proto-errors", 20, "always remove endpoint after this many consecutive protocol errors") |
|
|
|
|
registerParam("min-proto-errors", 4, "do not consider removing an endpoint if it does not have this many consecutive protocol errors") |
|
|
|
|
|
|
|
|
|
CfgRegister("no-response-delay-ms", 2000, "wait for this number of ms if an endpoint does not respond") |
|
|
|
|
CfgRegister("read-error-delay-ms", 5000, "wait for this number of ms if an endpoint returns a read error") |
|
|
|
|
CfgRegister("protocol-error-delay-ms", 5000, "wait for this number of ms if an endpoint returns a protocol error") |
|
|
|
|
registerParam("read-error-ratio", 0.25, "keep endpoints with a read error if their read error ratio is lower than this value") |
|
|
|
|
registerParam("max-read-errors", 20, "always remove endpoint after this many consecutive read errors") |
|
|
|
|
registerParam("min-read-errors", 3, "do not consider removing an endpoint if it does not have this many consecutive read errors") |
|
|
|
|
|
|
|
|
|
registerParam("no-response-delay-ms", 2000, "wait for this number of ms if an endpoint does not respond") |
|
|
|
|
registerParam("read-error-delay-ms", 5000, "wait for this number of ms if an endpoint returns a read error") |
|
|
|
|
registerParam("protocol-error-delay-ms", 5000, "wait for this number of ms if an endpoint returns a protocol error") |
|
|
|
|
} |
|
|
|
|