-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
noxnet: Add proxy for capturing the network data, decode some messages.
- Loading branch information
Showing
28 changed files
with
1,616 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/hex" | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/noxworld-dev/opennox-lib/noxnet" | ||
) | ||
|
||
var ( | ||
fIn = flag.String("i", "network.jsonl", "input file with packet capture") | ||
fOut = flag.String("o", "network-dec.jsonl", "output file for decoded packets") | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
if err := run(); err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func run() error { | ||
f, err := os.Open(*fIn) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
dec := json.NewDecoder(f) | ||
|
||
w, err := os.Create(*fOut) | ||
if err != nil { | ||
return err | ||
} | ||
defer w.Close() | ||
enc := json.NewEncoder(w) | ||
|
||
for { | ||
var r RecordIn | ||
err := dec.Decode(&r) | ||
if err == io.EOF { | ||
break | ||
} else if err != nil { | ||
return err | ||
} | ||
r2 := r.Decode() | ||
if err = enc.Encode(r2); err != nil { | ||
return err | ||
} | ||
} | ||
return w.Close() | ||
} | ||
|
||
type RecordIn struct { | ||
SrcID uint32 `json:"src_id"` | ||
DstID uint32 `json:"dst_id"` | ||
Src string `json:"src"` | ||
Dst string `json:"dst"` | ||
Data string `json:"data"` | ||
} | ||
|
||
func (r RecordIn) Decode() RecordOut { | ||
o := RecordOut{ | ||
SrcID: r.SrcID, | ||
DstID: r.DstID, | ||
Src: r.Src, | ||
Dst: r.Dst, | ||
Data: r.Data, | ||
} | ||
raw, err := hex.DecodeString(r.Data) | ||
if err != nil { | ||
return o | ||
} | ||
o.Len = len(raw) | ||
if len(raw) < 2 { | ||
return o | ||
} | ||
hdr, data := raw[:2], raw[2:] | ||
o.Hdr = hex.EncodeToString(hdr) | ||
if hdr[0] == 0xff { | ||
o.SID = 0xff | ||
} else { | ||
o.Reliable = hdr[0]&0x80 != 0 | ||
o.SID = hdr[0] &^ 0x80 | ||
o.Seq = hdr[1] | ||
} | ||
if len(data) == 1 { | ||
op := noxnet.Op(data[0]) | ||
if _, _, err := noxnet.DecodeAnyPacket(o.SrcID == 0, data); err != nil { | ||
s := op.String() | ||
o.Op = &s | ||
return o | ||
} | ||
} | ||
allSplit := true | ||
for len(data) != 0 { | ||
op := noxnet.Op(data[0]) | ||
sz := len(data) | ||
var v any | ||
lenOK := false | ||
if n := op.Len(); n >= 0 && n <= len(data) { | ||
sz = n + 1 | ||
lenOK = true | ||
} | ||
if m, n, err := noxnet.DecodeAnyPacket(o.SrcID == 0, data); err == nil && n > 0 { | ||
sz = n | ||
v = m | ||
lenOK = true | ||
} | ||
if !lenOK { | ||
allSplit = false | ||
} | ||
msg := data[:sz] | ||
data = data[sz:] | ||
m := Msg{ | ||
Op: op.String(), | ||
Len: len(msg), | ||
Data: hex.EncodeToString(msg), | ||
Fields: v, | ||
} | ||
o.Msgs = append(o.Msgs, m) | ||
} | ||
if allSplit { | ||
o.Data = "" | ||
} | ||
return o | ||
} | ||
|
||
type RecordOut struct { | ||
SrcID uint32 `json:"src_id"` | ||
DstID uint32 `json:"dst_id"` | ||
Src string `json:"src"` | ||
Dst string `json:"dst"` | ||
Hdr string `json:"hdr"` | ||
Reliable bool `json:"reliable"` | ||
SID byte `json:"sid"` | ||
Seq byte `json:"seq"` | ||
Len int `json:"len"` | ||
Op *string `json:"op,omitempty"` | ||
Msgs []Msg `json:"msgs,omitempty"` | ||
Data string `json:"data,omitempty"` | ||
} | ||
|
||
type Msg struct { | ||
Op string `json:"op,omitempty"` | ||
Fields any `json:"fields,omitempty"` | ||
Len int `json:"len"` | ||
Data string `json:"data"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# OpenNox net proxy | ||
|
||
This tool helps debug networking problems by sitting between Nox/OpenNox clients and the server. | ||
|
||
``` | ||
/ \<--| |<--| |<--| | | ||
|Client 1| | | | C1 proxy port | | | | ||
\ /-->| Proxy |-->| |-->| Real Nox | | ||
| server | | server | | ||
/ \-->| port |-->| |-->| | | ||
|Client 2| | | | C2 proxy port | | | | ||
\ /<--| |<--| |<--| | | ||
``` | ||
|
||
## Flow from client | ||
1. Packets from clients are accepted on the server proxy port. | ||
2. Proxy then allocates a unique proxy port for each client (since Nox uses ip+port for client id). | ||
3. Client packets are then sent from client proxy port to the real server. | ||
|
||
## Flow from server | ||
1. Packets are received on unique client proxy port. | ||
2. They are then sent from server proxy port to the client. | ||
|
||
## How to run | ||
|
||
```shell | ||
go run ./cmd/opennox-proxy --server=<server-ip>:18590 --host=0.0.0.0:18600 --file=network.jsonl | ||
``` | ||
|
||
This will run a proxy on port `18600`, which is not standard for Nox, thus server discovery will not find it. | ||
|
||
You must add the proxy address to `game_ip.txt` file in Nox directory (as `127.0.0.1:18600`). | ||
|
||
After this, you should see a new server in the server list, you will recognize it by "Proxy:" prefix. | ||
|
||
While you are connected to this server, all network messages are logged to `network.jsonl`. | ||
Once you're done with testing, disconnect from the proxy, and close it. | ||
|
||
Now you can run `go run ./cmd/opennox-packet-decode` that will decode known network messages | ||
in `network.jsonl` and will write them to `network-dec.jsonl`, which can then be inspected. |
Oops, something went wrong.