figuring out FLAP, SNAC, marshal/unmarshaling

This commit is contained in:
Artem Titoulenko 2021-11-16 16:44:29 -05:00
parent a23cdd7092
commit 5cf4d9dfcc
6 changed files with 212 additions and 39 deletions

View file

@ -0,0 +1,22 @@
package main
import (
"context"
"fmt"
)
var cipher = "hey wassup"
type AuthorizationRegistrationService struct{}
func (a *AuthorizationRegistrationService) HandleSNAC(ctx context.Context, snac *SNAC) {
// Request MD5 Auth Key
if snac.Header.Subtype == 0x06 {
fmt.Println("damn it's 0x06")
// cipherData := ByteString(cipher) // []byte
// snac := NewSNAC(0x17, 0x07, cipherData)
// resp := NewFLAP(2, snac)
}
}

70
flap.go Normal file
View file

@ -0,0 +1,70 @@
package main
import (
"bytes"
"context"
"encoding"
"encoding/binary"
"fmt"
)
var _ encoding.BinaryUnmarshaler = &FLAP{}
var _ encoding.BinaryMarshaler = &FLAP{}
type FLAPHeader struct {
Channel uint8
SequenceNumber uint16
DataLength uint16
}
type FLAP struct {
Header FLAPHeader
Data []byte
}
func NewFLAP(ctx context.Context, channel uint8, data []byte) *FLAP {
session := ctx.Value("session").(*Session)
session.SequenceNumber += 1
return &FLAP{
Header: FLAPHeader{
Channel: channel,
SequenceNumber: uint16(session.SequenceNumber),
DataLength: uint16(len(data)),
},
Data: data,
}
}
func (f *FLAP) UnmarshalBinary(data []byte) error {
buf := bytes.NewBuffer(data)
start, err := buf.ReadByte()
if err != nil {
return err
}
if start != 0x2a {
return fmt.Errorf("FLAP missing 0x2a header")
}
if err = binary.Read(buf, binary.BigEndian, &f.Header); err != nil {
return err
}
f.Data = buf.Bytes()
return nil
}
func (f *FLAP) MarshalBinary() ([]byte, error) {
var buf bytes.Buffer
buf.WriteByte(0x2a)
binary.Write(&buf, binary.BigEndian, f.Header)
n, err := buf.Write(f.Data)
if n != int(f.Header.DataLength) {
return nil, fmt.Errorf("needed to write %d bytes to buffer but wrote %d", f.Header.DataLength, n)
}
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}

56
main.go
View file

@ -1,9 +1,7 @@
package main package main
import ( import (
"bytes"
"context" "context"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -19,21 +17,10 @@ const (
SRV_ADDRESS = SRV_HOST + ":" + SRV_PORT SRV_ADDRESS = SRV_HOST + ":" + SRV_PORT
) )
type Session struct { var services = make(map[uint16]Service)
Conn net.Conn
GreetedClient bool
}
func NewSession(conn net.Conn) *Session { func init() {
return &Session{ services[0x17] = &AuthorizationRegistrationService{}
Conn: conn,
GreetedClient: false,
}
}
func (s *Session) Send(bytes []byte) {
fmt.Printf("-> %v\n%s\n\n", s.Conn.RemoteAddr(), prettyBytes(bytes))
s.Conn.Write(bytes)
} }
func main() { func main() {
@ -69,7 +56,9 @@ func main() {
func handleTCPConnection(ctx context.Context, conn net.Conn) { func handleTCPConnection(ctx context.Context, conn net.Conn) {
defer (func() { defer (func() {
recover() if r := recover(); r != nil {
log.Println("Error handling message: ", r.(error).Error())
}
conn.Close() conn.Close()
log.Printf("Closed connection to %v", conn.RemoteAddr()) log.Printf("Closed connection to %v", conn.RemoteAddr())
})() })()
@ -79,8 +68,9 @@ func handleTCPConnection(ctx context.Context, conn net.Conn) {
session := ctx.Value("session").(*Session) session := ctx.Value("session").(*Session)
if !session.GreetedClient { if !session.GreetedClient {
// send a hello // send a hello
hello := []byte{0x2a, 1, 0, 0, 0, 4, 0, 0, 0, 1} hello := NewFLAP(ctx, 1, []byte{0, 0, 0, 1})
session.Send(hello) err := session.Send(hello)
panicIfError(err)
session.GreetedClient = true session.GreetedClient = true
} }
@ -100,26 +90,18 @@ func handleTCPConnection(ctx context.Context, conn net.Conn) {
} }
func handleMessage(ctx context.Context, buf []byte) { func handleMessage(ctx context.Context, buf []byte) {
messageBuf := bytes.NewBuffer(buf) flap := &FLAP{}
flap.UnmarshalBinary(buf)
start, err := messageBuf.ReadByte() if flap.Header.Channel == 1 {
} else if flap.Header.Channel == 2 {
snac := &SNAC{}
err := snac.UnmarshalBinary(flap.Data)
panicIfError(err) panicIfError(err)
if start != 0x2a {
log.Println("FLAP message missing leading 0x2a") if service, ok := services[snac.Header.Family]; ok {
return service.HandleSNAC(ctx, snac)
} }
type FLAP struct {
Channel uint8
SequenceNumber uint16
DataLength uint16
} }
flap := FLAP{}
panicIfError(binary.Read(messageBuf, binary.BigEndian, &flap))
// Start parsing FLAP header
log.Println("Message for channel: ", flap.Channel)
log.Println("Datagram Sequence Number: ", flap.SequenceNumber)
log.Println("Data Length: ", flap.DataLength)
} }

9
service.go Normal file
View file

@ -0,0 +1,9 @@
package main
import (
"context"
)
type Service interface {
HandleSNAC(context.Context, *SNAC)
}

32
session.go Normal file
View file

@ -0,0 +1,32 @@
package main
import (
"encoding"
"fmt"
"net"
)
type Session struct {
Conn net.Conn
SequenceNumber uint16
GreetedClient bool
}
func NewSession(conn net.Conn) *Session {
return &Session{
Conn: conn,
SequenceNumber: 0,
GreetedClient: false,
}
}
func (s *Session) Send(m encoding.BinaryMarshaler) error {
bytes, err := m.MarshalBinary()
if err != nil {
return err
}
fmt.Printf("-> %v\n%s\n\n", s.Conn.RemoteAddr(), prettyBytes(bytes))
_, err = s.Conn.Write(bytes)
return err
}

58
snac.go Normal file
View file

@ -0,0 +1,58 @@
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
type SNACHeader struct {
Family uint16
Subtype uint16
Flags uint16
RequestID uint16
}
type SNAC struct {
Header SNACHeader
Data []byte
}
func NewSNAC(family uint16, subtype uint16, data []byte) *SNAC {
return &SNAC{
Header: SNACHeader{
Family: family,
Subtype: subtype,
Flags: 0,
RequestID: 0,
},
Data: data,
}
}
func (s *SNAC) MarshalBinary() ([]byte, error) {
var buf bytes.Buffer
binary.Write(&buf, binary.BigEndian, s.Header)
n, err := buf.Write(s.Data)
if n != len(s.Data) {
return nil, fmt.Errorf("needed to write %d bytes to buffer but wrote %d", len(s.Data), n)
}
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (s *SNAC) UnmarshalBinary(data []byte) error {
buf := bytes.NewBuffer(data)
if err := binary.Read(buf, binary.BigEndian, &s.Header); s != nil {
return err
}
s.Data = buf.Bytes()
return nil
}