diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2021-08-27 18:59:27 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2021-08-27 18:59:27 +0200 |
commit | b21345fba99d38c5e5ade695e32fc9e23ea48e98 (patch) | |
tree | 3d90d8abd9d356109d8690c5babd481abb363b55 /server_conn.go | |
parent | ca7c62308867f27a607fd17d72f926fcda05bb32 (diff) |
Basic authentication server and content multiplexer
Diffstat (limited to 'server_conn.go')
-rw-r--r-- | server_conn.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/server_conn.go b/server_conn.go new file mode 100644 index 0000000..d2d39b1 --- /dev/null +++ b/server_conn.go @@ -0,0 +1,142 @@ +package main + +import ( + "errors" + "fmt" + "log" + "net" + "time" + + "github.com/HimbeerserverDE/srp" + "github.com/anon55555/mt" +) + +type serverConn struct { + mt.Peer + clt *clientConn + + state clientState + name string + initCh chan struct{} + + auth struct { + method mt.AuthMethods + salt, srpA, a, srpK []byte + } +} + +func (sc *serverConn) client() *clientConn { return sc.clt } + +func (sc *serverConn) init() <-chan struct{} { return sc.initCh } + +func (sc *serverConn) log(dir, msg string) { + log.Printf("{←|⇶} %s {%s} %s", dir, sc.name, msg) +} + +func handleSrv(sc *serverConn) { + if sc.client() == nil { + sc.log("-->", "no associated client") + } + + go func() { + for sc.state == csCreated { + sc.SendCmd(&mt.ToSrvInit{ + SerializeVer: latestSerializeVer, + MinProtoVer: latestProtoVer, + MaxProtoVer: latestProtoVer, + PlayerName: sc.client().name, + }) + time.Sleep(500 * time.Millisecond) + } + }() + + for { + pkt, err := sc.Recv() + if err != nil { + if errors.Is(err, net.ErrClosed) { + sc.log("<->", "disconnect") + break + } + + sc.log("-->", err.Error()) + continue + } + + switch cmd := pkt.Cmd.(type) { + case *mt.ToCltHello: + if sc.auth.method != 0 { + sc.log("<--", "unexpected authentication") + sc.Close() + break + } + + sc.state++ + + if cmd.AuthMethods&mt.FirstSRP == mt.FirstSRP { + sc.auth.method = mt.FirstSRP + } else { + sc.auth.method = mt.SRP + } + + if cmd.SerializeVer != latestSerializeVer { + sc.log("<--", "invalid serializeVer") + break + } + + switch sc.auth.method { + case mt.SRP: + sc.auth.srpA, sc.auth.a, err = srp.InitiateHandshake() + if err != nil { + sc.log("-->", err.Error()) + break + } + + sc.SendCmd(&mt.ToSrvSRPBytesA{ + A: sc.auth.srpA, + NoSHA1: true, + }) + case mt.FirstSRP: + salt, verifier, err := srp.NewClient([]byte(sc.client().name), []byte{}) + if err != nil { + sc.log("-->", err.Error()) + break + } + + sc.SendCmd(&mt.ToSrvFirstSRP{ + Salt: salt, + Verifier: verifier, + EmptyPasswd: true, + }) + default: + sc.log("<->", "invalid auth method") + sc.Close() + } + case *mt.ToCltSRPBytesSaltB: + if sc.auth.method != mt.SRP { + sc.log("<--", "multiple authentication attempts") + break + } + + sc.auth.srpK, err = srp.CompleteHandshake(sc.auth.srpA, sc.auth.a, []byte(sc.client().name), []byte{}, cmd.Salt, cmd.B) + if err != nil { + sc.log("-->", err.Error()) + break + } + + M := srp.ClientProof([]byte(sc.client().name), cmd.Salt, sc.auth.srpA, cmd.B, sc.auth.srpK) + if M == nil { + sc.log("<--", "SRP safety check fail") + break + } + + sc.SendCmd(&mt.ToSrvSRPBytesM{ + M: M, + }) + case *mt.ToCltDisco: + sc.log("<--", fmt.Sprintf("deny access %+v", cmd)) + case *mt.ToCltAcceptAuth: + sc.auth.method = 0 + sc.SendCmd(&mt.ToSrvInit2{Lang: sc.client().lang}) + } + } +} |