📶 [WIP] RouterOS WinBox bruteforce
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mtbf/task.go

257 lines
7.8 KiB

2 years ago
package main
import (
2 years ago
"container/list"
"strconv"
2 years ago
"sync"
"time"
)
2 years ago
// deferredTasks is a list of tasks that were deferred for processing to a later time.
// This usually happens due to connection errors, protocol errors or per-endpoint limits.
var deferredTasks *list.List
// taskMutex is a mutex for safe handling of deferred task list.
var taskMutex sync.Mutex
func init() {
deferredTasks = list.New()
}
2 years ago
// TaskEvent represents all events that can be issued on a Task.
type TaskEvent int
const (
TE_Generic TaskEvent = iota // undefined or no event
// These should terminate a task instantly.
TE_NoResponse // connect timed out
TE_ReadFailed // read failed or timed out
TE_NoService // endpoint does not provide selected service
TE_ProtocolError // a service module reported an error during auth attempt
TE_Bad // auth attempt completed successfully but credentials were wrong
TE_Good // auth attempt completed successfully and the credentials are correct
// TODO: proxying
TE_ProxyNoResponse // cannot connect to a proxy
TE_ProxyError // proxy failed during an exchange with the endpoint
TE_ProxyInvalidAuth // authenticated proxy rejected our credentials
// These serve as "hints" - they do not necessarily need to
// terminate a task, but they can still provide useful
// information about an endpoint or a service.
TH_NoSuchLogin // login in this task is not present or not valid on a service
TH_LoadExceeded // endpoint or service cannot handle this attempt rate
TH_Banned // got banned from a service, should try another proxy or wait out the delay
TH_WaitRequest // request for a grace time
// These are still hints, but they occur very frequently on a Task's normal lifecycle,
// effectively making these sort of "notifications" rather than hints.
TN_Connected // successfully connected to an endpoint
TN_ProxyConnected // successfully connected to a proxy
)
func (ev TaskEvent) String() string {
return [...]string{"Generic", "No response", "Read failed", "No Service", "Protocol error",
"Bad", "Good", "No response from Proxy", "Error from Proxy", "Invalid auth from Proxy",
"No Such login (hint)", "Load exceeded (hint)", "Banned (hint)", "Wait request (hint)",
"Connected (notify)", "Connected from Proxy (notify)"}[ev]
}
// A Task represents a single unit of workload.
// Every Task is linked to an Endpoint.
type Task struct {
2 years ago
e *Endpoint
login string
password string
deferUntil time.Time
numDeferrals int
listElement *list.Element // position in list
thread int // thread index
2 years ago
}
// String returns a string representation of a Task.
func (task *Task) String() string {
if task == nil {
return "<empty task>"
} else {
s := task.e.String() + "@" + task.login + ":" + task.password
if task.thread > 0 {
s = "[" + strconv.Itoa(task.thread) + "] " + s
}
return s
2 years ago
}
}
// Defer sends a Task to the deferred queue.
func (task *Task) Defer(addTime time.Duration) {
task.deferUntil = time.Now().Add(addTime)
task.numDeferrals++
2 years ago
maxDeferrals := getParamInt("task-max-deferrals")
2 years ago
if maxDeferrals != -1 && task.numDeferrals >= maxDeferrals {
log("task", 5, "giving up on task \"%v\" because it has exhausted its deferral limit (%v)", task, maxDeferrals)
return
}
log("task", 5, "deferring task \"%v\" for %v", task, addTime)
taskMutex.Lock()
defer taskMutex.Unlock()
2 years ago
if task.listElement == nil {
task.listElement = deferredTasks.PushBack(task)
}
2 years ago
}
// EventWithParm tells a Task (and its underlying Endpoint) that
// something important has happened, or a hint has been acquired.
// Returns False if an event resulted in a deletion of its Task.
func (task *Task) EventWithParm(event TaskEvent, parm any) bool {
log("task", 4, "task event for \"%v\": %v", task, event)
if event == TE_Generic {
return true // do not process generic events
}
2 years ago
endpointOk := task.e.EventWithParm(event, parm) // notify the endpoint first
2 years ago
logIf(!endpointOk, "task", 4, "endpoint got deleted during a task event for \"%v\"", task)
2 years ago
switch event {
// on these events, defer a Task only if its Endpoint is being kept
case TE_NoResponse:
2 years ago
if endpointOk {
task.Defer(getParamDurationMS("no-response-delay-ms"))
2 years ago
}
case TE_ReadFailed:
2 years ago
if endpointOk {
task.Defer(getParamDurationMS("read-error-delay-ms"))
2 years ago
}
case TE_ProtocolError:
2 years ago
if endpointOk {
task.Defer(getParamDurationMS("protocol-error-delay-ms"))
2 years ago
}
// report about a bad/good auth result
case TE_Good:
RegisterResult(task, true)
case TE_Bad:
RegisterResult(task, false)
// wait request has occurred: stop processing and instantly wait on a thread
case TH_WaitRequest:
log("task", 4, "wait request for \"%v\": sleeping for %v", task, parm.(time.Duration))
time.Sleep(parm.(time.Duration))
}
2 years ago
return endpointOk
2 years ago
}
// Event is a parameterless version of EventWithParm.
func (task *Task) Event(event TaskEvent) bool {
return task.EventWithParm(event, 0)
}
// GetDeferredTask retrieves a Task from the deferred queue.
func GetDeferredTask() (task *Task, waitTime time.Duration) {
currentTime := time.Now()
2 years ago
if deferredTasks.Len() == 0 {
2 years ago
log("task", 5, "deferred task list is empty")
return nil, 0
}
2 years ago
minWaitTime := time.Time{}
2 years ago
2 years ago
for e := deferredTasks.Front(); e != nil; e = e.Next() {
dt := e.Value.(*Task)
if minWaitTime.IsZero() || (dt.deferUntil.Before(minWaitTime) && dt.deferUntil.After(currentTime)) {
minWaitTime = dt.deferUntil
2 years ago
}
2 years ago
if dt.deferUntil.Before(currentTime) && (dt.e.delayUntil.IsZero() || dt.e.delayUntil.Before(currentTime)) {
deferredTasks.Remove(e)
return dt, 0
2 years ago
}
}
2 years ago
return nil, minWaitTime.Sub(currentTime)
2 years ago
}
// FetchTaskComponents returns all components needed to build a Task.
func FetchTaskComponents() (ep *Endpoint, login string, password string, waitTime time.Duration) {
var empty bool
log("task", 5, "fetching components for a new task")
2 years ago
ep, waitTime = FetchEndpoint()
if ep == nil {
return nil, "", "", waitTime
}
log("task", 5, "fetched endpoint: \"%v\"", ep)
hasLogin := false
2 years ago
for {
log("task", 5, "fetching password for \"%v\"", ep)
password, empty = SrcPassword.FetchOne(&ep.passwordPos, true)
if !empty {
log("task", 5, "got password for \"%v\": %v, fetching login", ep, password)
if !hasLogin {
login, empty = SrcLogin.FetchOne(&ep.loginPos, false)
}
2 years ago
break
}
log("task", 5, "out of passwords for \"%v\": resetting passwords and fetching new login", ep)
2 years ago
ep.passwordPos.Reset()
login, empty = SrcLogin.FetchOne(&ep.loginPos, true)
hasLogin = true
if empty {
break
}
2 years ago
}
if !empty {
log("task", 5, "got login for \"%v\": %v", ep, login)
return ep, login, password, 0
} else {
log("task", 5, "out of logins for \"%v\": exhausting endpoint", ep)
ep.Exhausted()
return FetchTaskComponents() // attempt to fetch again with a new endpoint
2 years ago
}
}
// CreateTask creates a new Task element. It searches through deferred queue first,
// then, if nothing was found, it assembles a new (Endpoint, login, password) combination.
func CreateTask(threadIdx int) (task *Task, delay time.Duration) {
2 years ago
taskMutex.Lock()
defer taskMutex.Unlock()
task, delayDeferred := GetDeferredTask()
if task != nil {
log("task", 4, "new task (deferred): %v", task)
return task, 0
}
2 years ago
ep, login, password, delayEndpoint := FetchTaskComponents()
2 years ago
if ep == nil {
2 years ago
if delayDeferred == 0 && delayEndpoint == 0 {
2 years ago
log("task", 4, "cannot build task, no endpoint")
return nil, 0
2 years ago
} else if delayDeferred > delayEndpoint || delayDeferred == 0 {
log("task", 4, "delaying task creation (by endpoint delay) for %v", delayEndpoint)
return nil, delayEndpoint
2 years ago
} else {
log("task", 4, "delaying task creation (by deferred delay) for %v", delayDeferred)
return nil, delayDeferred
}
}
t := Task{e: ep, login: login, password: password, thread: threadIdx}
2 years ago
log("task", 4, "new task: %v", &t)
return &t, 0
}