Smarter logging (anon5)

master
HimbeerserverDE 2021-09-13 12:14:11 +02:00
parent 9f5a9f8077
commit 2004b786dd
No known key found for this signature in database
GPG Key ID: 1A651504791E6A8B
12 changed files with 137 additions and 149 deletions

View File

@ -43,10 +43,10 @@ func onChatMsg(cc *ClientConn, cmd *mt.ToSrvChatMsg) (string, bool) {
v[i+2] = arg v[i+2] = arg
} }
cc.Log("-->", v...) cc.Log("->", v...)
if !ChatCmdExists(cmdName) { if !ChatCmdExists(cmdName) {
cc.Log("<--", "unknown command", cmdName) cc.Log("<-", "unknown command", cmdName)
return "Command not found.", true return "Command not found.", true
} }
@ -56,7 +56,7 @@ func onChatMsg(cc *ClientConn, cmd *mt.ToSrvChatMsg) (string, bool) {
cmd := chatCmds[cmdName] cmd := chatCmds[cmdName]
if !cc.HasPerms(cmd.Perm) { if !cc.HasPerms(cmd.Perm) {
cc.Log("<--", "deny command", cmdName) cc.Log("<-", "deny command", cmdName)
return fmt.Sprintf("Missing permission %s.", cmd.Perm), true return fmt.Sprintf("Missing permission %s.", cmd.Perm), true
} }
@ -78,7 +78,7 @@ func onTelnetMsg(tlog func(dir string, v ...interface{}), w io.Writer, msg strin
} }
if !ChatCmdExists(cmdName) { if !ChatCmdExists(cmdName) {
tlog("<--", "unknown command", cmdName) tlog("<-", "unknown command", cmdName)
return "Command not found.\n" return "Command not found.\n"
} }

View File

@ -3,10 +3,10 @@ package proxy
import ( import (
"crypto/subtle" "crypto/subtle"
"errors" "errors"
"fmt"
"log" "log"
"net" "net"
"regexp" "regexp"
"strings"
"sync" "sync"
"github.com/HimbeerserverDE/srp" "github.com/HimbeerserverDE/srp"
@ -29,6 +29,8 @@ type ClientConn struct {
srv *ServerConn srv *ServerConn
mu sync.RWMutex mu sync.RWMutex
logger *log.Logger
cstate clientState cstate clientState
cstateMu sync.RWMutex cstateMu sync.RWMutex
name string name string
@ -103,21 +105,7 @@ func (cc *ClientConn) Init() <-chan struct{} { return cc.initCh }
// Log logs an interaction with the ClientConn. // Log logs an interaction with the ClientConn.
// dir indicates the direction of the interaction. // dir indicates the direction of the interaction.
func (cc *ClientConn) Log(dir string, v ...interface{}) { func (cc *ClientConn) Log(dir string, v ...interface{}) {
if cc.Name() != "" { cc.logger.Println(append([]interface{}{dir}, v...)...)
format := "{%s, %s} %s {←|⇶}"
format += strings.Repeat(" %v", len(v))
log.Printf(format, append([]interface{}{
cc.Name(),
cc.RemoteAddr(),
dir,
}, v...)...)
} else {
format := "{%s} %s {←|⇶}"
format += strings.Repeat(" %v", len(v))
log.Printf(format, append([]interface{}{cc.RemoteAddr(), dir}, v...)...)
}
} }
func handleClt(cc *ClientConn) { func handleClt(cc *ClientConn) {
@ -152,20 +140,20 @@ func handleClt(cc *ClientConn) {
break break
} }
cc.Log("-->", err) cc.Log("->", err)
continue continue
} }
switch cmd := pkt.Cmd.(type) { switch cmd := pkt.Cmd.(type) {
case *mt.ToSrvInit: case *mt.ToSrvInit:
if cc.state() > csCreated { if cc.state() > csCreated {
cc.Log("-->", "duplicate init") cc.Log("->", "duplicate init")
break break
} }
cc.setState(csInit) cc.setState(csInit)
if cmd.SerializeVer != latestSerializeVer { if cmd.SerializeVer != latestSerializeVer {
cc.Log("<--", "invalid serializeVer") cc.Log("<-", "invalid serializeVer")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnsupportedVer}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnsupportedVer})
select { select {
@ -178,7 +166,7 @@ func handleClt(cc *ClientConn) {
} }
if cmd.MaxProtoVer < latestProtoVer { if cmd.MaxProtoVer < latestProtoVer {
cc.Log("<--", "invalid protoVer") cc.Log("<-", "invalid protoVer")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnsupportedVer}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnsupportedVer})
select { select {
@ -191,7 +179,7 @@ func handleClt(cc *ClientConn) {
} }
if len(cmd.PlayerName) == 0 || len(cmd.PlayerName) > maxPlayerNameLen { if len(cmd.PlayerName) == 0 || len(cmd.PlayerName) > maxPlayerNameLen {
cc.Log("<--", "invalid player name length") cc.Log("<-", "invalid player name length")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.BadName}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.BadName})
select { select {
@ -204,7 +192,7 @@ func handleClt(cc *ClientConn) {
} }
if ok, _ := regexp.MatchString(playerNameChars, cmd.PlayerName); !ok { if ok, _ := regexp.MatchString(playerNameChars, cmd.PlayerName); !ok {
cc.Log("<--", "invalid player name") cc.Log("<-", "invalid player name")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.BadNameChars}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.BadNameChars})
select { select {
@ -217,9 +205,10 @@ func handleClt(cc *ClientConn) {
} }
cc.name = cmd.PlayerName cc.name = cmd.PlayerName
cc.logger.SetPrefix(fmt.Sprintf("[%s %s] ", cc.RemoteAddr(), cc.Name()))
if authIface.Banned(cc.RemoteAddr().(*net.UDPAddr)) { if authIface.Banned(cc.RemoteAddr().(*net.UDPAddr)) {
cc.Log("<--", "banned") cc.Log("<-", "banned")
cc.Kick("Banned by proxy.") cc.Kick("Banned by proxy.")
break break
} }
@ -227,7 +216,7 @@ func handleClt(cc *ClientConn) {
playersMu.Lock() playersMu.Lock()
_, ok := players[cc.Name()] _, ok := players[cc.Name()]
if ok { if ok {
cc.Log("<--", "already connected") cc.Log("<-", "already connected")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.AlreadyConnected}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.AlreadyConnected})
select { select {
@ -244,7 +233,7 @@ func handleClt(cc *ClientConn) {
playersMu.Unlock() playersMu.Unlock()
if cc.Name() == "singleplayer" { if cc.Name() == "singleplayer" {
cc.Log("<--", "name is singleplayer") cc.Log("<-", "name is singleplayer")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.BadName}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.BadName})
select { select {
@ -258,7 +247,7 @@ func handleClt(cc *ClientConn) {
// user limit // user limit
if len(players) >= Conf().UserLimit { if len(players) >= Conf().UserLimit {
cc.Log("<--", "player limit reached") cc.Log("<-", "player limit reached")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.TooManyClts}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.TooManyClts})
select { select {
@ -286,7 +275,7 @@ func handleClt(cc *ClientConn) {
case *mt.ToSrvFirstSRP: case *mt.ToSrvFirstSRP:
if cc.state() == csInit { if cc.state() == csInit {
if cc.auth.method != mt.FirstSRP { if cc.auth.method != mt.FirstSRP {
cc.Log("-->", "unauthorized password change") cc.Log("->", "unauthorized password change")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnexpectedData}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnexpectedData})
select { select {
@ -304,7 +293,7 @@ func handleClt(cc *ClientConn) {
}{} }{}
if cmd.EmptyPasswd && Conf().RequirePasswd { if cmd.EmptyPasswd && Conf().RequirePasswd {
cc.Log("<--", "empty password disallowed") cc.Log("<-", "empty password disallowed")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.EmptyPasswd}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.EmptyPasswd})
select { select {
@ -317,7 +306,7 @@ func handleClt(cc *ClientConn) {
} }
if err := authIface.SetPasswd(cc.Name(), cmd.Salt, cmd.Verifier); err != nil { if err := authIface.SetPasswd(cc.Name(), cmd.Salt, cmd.Verifier); err != nil {
cc.Log("<--", "set password fail") cc.Log("<-", "set password fail")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.SrvErr}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.SrvErr})
select { select {
@ -329,7 +318,7 @@ func handleClt(cc *ClientConn) {
break break
} }
cc.Log("-->", "set password") cc.Log("->", "set password")
cc.SendCmd(&mt.ToCltAcceptAuth{ cc.SendCmd(&mt.ToCltAcceptAuth{
PlayerPos: mt.Pos{0, 5, 0}, PlayerPos: mt.Pos{0, 5, 0},
MapSeed: 0, MapSeed: 0,
@ -338,30 +327,30 @@ func handleClt(cc *ClientConn) {
}) })
} else { } else {
if cc.state() < csSudo { if cc.state() < csSudo {
cc.Log("-->", "unauthorized sudo action") cc.Log("->", "unauthorized sudo action")
break break
} }
cc.setState(cc.state() - 1) cc.setState(cc.state() - 1)
if err := authIface.SetPasswd(cc.Name(), cmd.Salt, cmd.Verifier); err != nil { if err := authIface.SetPasswd(cc.Name(), cmd.Salt, cmd.Verifier); err != nil {
cc.Log("<--", "change password fail") cc.Log("<-", "change password fail")
cc.SendChatMsg("Password change failed or unavailable.") cc.SendChatMsg("Password change failed or unavailable.")
break break
} }
cc.Log("-->", "change password") cc.Log("->", "change password")
cc.SendChatMsg("Password change successful.") cc.SendChatMsg("Password change successful.")
} }
case *mt.ToSrvSRPBytesA: case *mt.ToSrvSRPBytesA:
wantSudo := cc.state() == csActive wantSudo := cc.state() == csActive
if cc.state() != csInit && cc.state() != csActive { if cc.state() != csInit && cc.state() != csActive {
cc.Log("-->", "unexpected authentication") cc.Log("->", "unexpected authentication")
break break
} }
if !wantSudo && cc.auth.method != mt.SRP { if !wantSudo && cc.auth.method != mt.SRP {
cc.Log("<--", "multiple authentication attempts") cc.Log("<-", "multiple authentication attempts")
if wantSudo { if wantSudo {
cc.SendCmd(&mt.ToCltDenySudoMode{}) cc.SendCmd(&mt.ToCltDenySudoMode{})
break break
@ -378,7 +367,7 @@ func handleClt(cc *ClientConn) {
} }
if !cmd.NoSHA1 { if !cmd.NoSHA1 {
cc.Log("<--", "unsupported SHA1 auth") cc.Log("<-", "unsupported SHA1 auth")
break break
} }
@ -386,7 +375,7 @@ func handleClt(cc *ClientConn) {
salt, verifier, err := authIface.Passwd(cc.Name()) salt, verifier, err := authIface.Passwd(cc.Name())
if err != nil { if err != nil {
cc.Log("<--", "SRP data retrieval fail") cc.Log("<-", "SRP data retrieval fail")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.SrvErr}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.SrvErr})
select { select {
@ -402,7 +391,7 @@ func handleClt(cc *ClientConn) {
cc.auth.srpA = cmd.A cc.auth.srpA = cmd.A
cc.auth.srpB, _, cc.auth.srpK, err = srp.Handshake(cc.auth.srpA, verifier) cc.auth.srpB, _, cc.auth.srpK, err = srp.Handshake(cc.auth.srpA, verifier)
if err != nil || cc.auth.srpB == nil { if err != nil || cc.auth.srpB == nil {
cc.Log("<--", "SRP safety check fail") cc.Log("<-", "SRP safety check fail")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnexpectedData}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.UnexpectedData})
select { select {
@ -422,12 +411,12 @@ func handleClt(cc *ClientConn) {
wantSudo := cc.state() == csActive wantSudo := cc.state() == csActive
if cc.state() != csInit && cc.state() != csActive { if cc.state() != csInit && cc.state() != csActive {
cc.Log("-->", "unexpected authentication") cc.Log("->", "unexpected authentication")
break break
} }
if cc.auth.method != mt.SRP { if cc.auth.method != mt.SRP {
cc.Log("<--", "multiple authentication attempts") cc.Log("<-", "multiple authentication attempts")
if wantSudo { if wantSudo {
cc.SendCmd(&mt.ToCltDenySudoMode{}) cc.SendCmd(&mt.ToCltDenySudoMode{})
break break
@ -464,12 +453,12 @@ func handleClt(cc *ClientConn) {
} }
} else { } else {
if wantSudo { if wantSudo {
cc.Log("<--", "invalid password (sudo)") cc.Log("<-", "invalid password (sudo)")
cc.SendCmd(&mt.ToCltDenySudoMode{}) cc.SendCmd(&mt.ToCltDenySudoMode{})
break break
} }
cc.Log("<--", "invalid password") cc.Log("<-", "invalid password")
ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.WrongPasswd}) ack, _ := cc.SendCmd(&mt.ToCltDisco{Reason: mt.WrongPasswd})
select { select {
@ -483,7 +472,7 @@ func handleClt(cc *ClientConn) {
case *mt.ToSrvInit2: case *mt.ToSrvInit2:
cc.itemDefs, cc.aliases, cc.nodeDefs, cc.p0Map, cc.p0SrvMap, cc.media, err = muxContent(cc.Name()) cc.itemDefs, cc.aliases, cc.nodeDefs, cc.p0Map, cc.p0SrvMap, cc.media, err = muxContent(cc.Name())
if err != nil { if err != nil {
cc.Log("<--", err.Error()) cc.Log("<-", err.Error())
cc.Kick("Content multiplexing failed.") cc.Kick("Content multiplexing failed.")
break break
} }
@ -546,7 +535,7 @@ func handleClt(cc *ClientConn) {
close(cc.initCh) close(cc.initCh)
case *mt.ToSrvInteract: case *mt.ToSrvInteract:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
@ -557,7 +546,7 @@ func handleClt(cc *ClientConn) {
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvChatMsg: case *mt.ToSrvChatMsg:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
@ -569,73 +558,73 @@ func handleClt(cc *ClientConn) {
} }
case *mt.ToSrvDeletedBlks: case *mt.ToSrvDeletedBlks:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvFallDmg: case *mt.ToSrvFallDmg:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvGotBlks: case *mt.ToSrvGotBlks:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvJoinModChan: case *mt.ToSrvJoinModChan:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvLeaveModChan: case *mt.ToSrvLeaveModChan:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvMsgModChan: case *mt.ToSrvMsgModChan:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvNodeMetaFields: case *mt.ToSrvNodeMetaFields:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvPlayerPos: case *mt.ToSrvPlayerPos:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvRespawn: case *mt.ToSrvRespawn:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvInvAction: case *mt.ToSrvInvAction:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvInvFields: case *mt.ToSrvInvFields:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)
case *mt.ToSrvSelectItem: case *mt.ToSrvSelectItem:
if cc.server() == nil { if cc.server() == nil {
cc.Log("-->", "no server") cc.Log("->", "no server")
break break
} }
cc.server().SendCmd(cmd) cc.server().SendCmd(cmd)

View File

@ -8,13 +8,15 @@ import (
"sync" "sync"
) )
const defaultCmdPrefix = ">" const (
const defaultSendInterval = 0.09 defaultCmdPrefix = ">"
const defaultUserLimit = 10 defaultSendInterval = 0.09
const defaultAuthBackend = "sqlite3" defaultUserLimit = 10
const defaultTelnetAddr = "[::1]:40010" defaultAuthBackend = "sqlite3"
const defaultBindAddr = ":40000" defaultTelnetAddr = "[::1]:40010"
const defaultListInterval = 300 defaultBindAddr = ":40000"
defaultListInterval = 300
)
var config Config var config Config
var configMu sync.RWMutex var configMu sync.RWMutex
@ -115,6 +117,6 @@ func LoadConfig() error {
return err return err
} }
log.Print("{←|⇶} load config") log.Print("load config")
return nil return nil
} }

View File

@ -1,6 +1,8 @@
package proxy package proxy
import ( import (
"fmt"
"log"
"net" "net"
"github.com/anon55555/mt" "github.com/anon55555/mt"
@ -15,8 +17,10 @@ func connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
} }
cc.mu.RUnlock() cc.mu.RUnlock()
prefix := fmt.Sprintf("[server %s] ", name)
sc := &ServerConn{ sc := &ServerConn{
Peer: mt.Connect(conn), Peer: mt.Connect(conn),
logger: log.New(logWriter, prefix, log.LstdFlags|log.Lmsgprefix),
initCh: make(chan struct{}), initCh: make(chan struct{}),
clt: cc, clt: cc,
name: name, name: name,
@ -26,7 +30,7 @@ func connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
huds: make(map[mt.HUDID]mt.HUDType), huds: make(map[mt.HUDID]mt.HUDType),
playerList: make(map[string]struct{}), playerList: make(map[string]struct{}),
} }
sc.Log("-->", "connect") sc.Log("->", "connect")
cc.mu.Lock() cc.mu.Lock()
cc.srv = sc cc.srv = sc
@ -37,8 +41,10 @@ func connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
} }
func connectContent(conn net.Conn, name, userName string) (*contentConn, error) { func connectContent(conn net.Conn, name, userName string) (*contentConn, error) {
prefix := fmt.Sprintf("[content %s] ", name)
cc := &contentConn{ cc := &contentConn{
Peer: mt.Connect(conn), Peer: mt.Connect(conn),
logger: log.New(logWriter, prefix, log.LstdFlags|log.Lmsgprefix),
doneCh: make(chan struct{}), doneCh: make(chan struct{}),
name: name, name: name,
userName: userName, userName: userName,

View File

@ -30,6 +30,8 @@ type mediaFile struct {
type contentConn struct { type contentConn struct {
mt.Peer mt.Peer
logger *log.Logger
cstate clientState cstate clientState
cstateMu sync.RWMutex cstateMu sync.RWMutex
name, userName string name, userName string
@ -69,10 +71,7 @@ func (cc *contentConn) addDefaultTextures() {
} }
func (cc *contentConn) log(dir string, v ...interface{}) { func (cc *contentConn) log(dir string, v ...interface{}) {
format := "{←|⇶} %s {%s}" cc.logger.Println(append([]interface{}{dir}, v...)...)
format += strings.Repeat(" %v", len(v))
log.Printf(format, append([]interface{}{dir, cc.name}, v...)...)
} }
func handleContent(cc *contentConn) { func handleContent(cc *contentConn) {
@ -86,7 +85,7 @@ func handleContent(cc *contentConn) {
select { select {
case <-init: case <-init:
case <-time.After(10 * time.Second): case <-time.After(10 * time.Second):
cc.log("-->", "timeout") cc.log("->", "timeout")
cc.Close() cc.Close()
} }
}(init) }(init)
@ -112,14 +111,14 @@ func handleContent(cc *contentConn) {
break break
} }
cc.log("-->", err) cc.log("->", err)
continue continue
} }
switch cmd := pkt.Cmd.(type) { switch cmd := pkt.Cmd.(type) {
case *mt.ToCltHello: case *mt.ToCltHello:
if cc.auth.method != 0 { if cc.auth.method != 0 {
cc.log("<--", "unexpected authentication") cc.log("<-", "unexpected authentication")
cc.Close() cc.Close()
break break
} }
@ -132,7 +131,7 @@ func handleContent(cc *contentConn) {
} }
if cmd.SerializeVer != latestSerializeVer { if cmd.SerializeVer != latestSerializeVer {
cc.log("<--", "invalid serializeVer") cc.log("<-", "invalid serializeVer")
break break
} }
@ -140,7 +139,7 @@ func handleContent(cc *contentConn) {
case mt.SRP: case mt.SRP:
cc.auth.srpA, cc.auth.a, err = srp.InitiateHandshake() cc.auth.srpA, cc.auth.a, err = srp.InitiateHandshake()
if err != nil { if err != nil {
cc.log("-->", err) cc.log("->", err)
break break
} }
@ -151,7 +150,7 @@ func handleContent(cc *contentConn) {
case mt.FirstSRP: case mt.FirstSRP:
salt, verifier, err := srp.NewClient([]byte(cc.userName), []byte{}) salt, verifier, err := srp.NewClient([]byte(cc.userName), []byte{})
if err != nil { if err != nil {
cc.log("-->", err) cc.log("->", err)
break break
} }
@ -166,19 +165,19 @@ func handleContent(cc *contentConn) {
} }
case *mt.ToCltSRPBytesSaltB: case *mt.ToCltSRPBytesSaltB:
if cc.auth.method != mt.SRP { if cc.auth.method != mt.SRP {
cc.log("<--", "multiple authentication attempts") cc.log("<-", "multiple authentication attempts")
break break
} }
cc.auth.srpK, err = srp.CompleteHandshake(cc.auth.srpA, cc.auth.a, []byte(cc.userName), []byte{}, cmd.Salt, cmd.B) cc.auth.srpK, err = srp.CompleteHandshake(cc.auth.srpA, cc.auth.a, []byte(cc.userName), []byte{}, cmd.Salt, cmd.B)
if err != nil { if err != nil {
cc.log("-->", err) cc.log("->", err)
break break
} }
M := srp.ClientProof([]byte(cc.userName), cmd.Salt, cc.auth.srpA, cmd.B, cc.auth.srpK) M := srp.ClientProof([]byte(cc.userName), cmd.Salt, cc.auth.srpA, cmd.B, cc.auth.srpK)
if M == nil { if M == nil {
cc.log("<--", "SRP safety check fail") cc.log("<-", "SRP safety check fail")
break break
} }
@ -186,7 +185,7 @@ func handleContent(cc *contentConn) {
M: M, M: M,
}) })
case *mt.ToCltDisco: case *mt.ToCltDisco:
cc.log("<--", "deny access", cmd) cc.log("<-", "deny access", cmd)
case *mt.ToCltAcceptAuth: case *mt.ToCltAcceptAuth:
cc.auth.method = 0 cc.auth.method = 0
cc.SendCmd(&mt.ToSrvInit2{}) cc.SendCmd(&mt.ToSrvInit2{})
@ -276,7 +275,7 @@ func (cc *ClientConn) sendMedia(filenames []string) {
} }
if !known { if !known {
cc.Log("-->", "request unknown media file") cc.Log("->", "request unknown media file")
continue continue
} }
} }

View File

@ -88,7 +88,7 @@ func announce(action string) error {
return err return err
} }
log.Print("{←|⇶} announce ", action) log.Println("announce", action)
return nil return nil
} }
@ -101,7 +101,7 @@ func init() {
<-t.C <-t.C
if !added { if !added {
if err := announce(listAdd); err != nil { if err := announce(listAdd); err != nil {
log.Print("{←|⇶} ", err) log.Print(err)
} }
added = true added = true
@ -109,7 +109,7 @@ func init() {
} }
if err := announce(listUpdate); err != nil { if err := announce(listUpdate); err != nil {
log.Print("{←|⇶} ", err) log.Print(err)
} }
} }
}() }()

View File

@ -2,6 +2,7 @@ package proxy
import ( import (
"fmt" "fmt"
"log"
"net" "net"
"sync" "sync"
@ -68,8 +69,10 @@ func (l *listener) accept() (*ClientConn, error) {
return nil, err return nil, err
} }
prefix := fmt.Sprintf("[%s] ", p.RemoteAddr())
cc := &ClientConn{ cc := &ClientConn{
Peer: p, Peer: p,
logger: log.New(logWriter, prefix, log.LstdFlags|log.Lmsgprefix),
initCh: make(chan struct{}), initCh: make(chan struct{}),
modChs: make(map[string]struct{}), modChs: make(map[string]struct{}),
} }
@ -86,7 +89,7 @@ func (l *listener) accept() (*ClientConn, error) {
delete(l.clts, cc) delete(l.clts, cc)
}() }()
cc.Log("-->", "connect") cc.Log("->", "connect")
go handleClt(cc) go handleClt(cc)
select { select {

13
log.go
View File

@ -6,6 +6,8 @@ import (
"path/filepath" "path/filepath"
) )
var logWriter *LogWriter
type LogWriter struct { type LogWriter struct {
f *os.File f *os.File
} }
@ -22,15 +24,18 @@ func (lw *LogWriter) Write(p []byte) (n int, err error) {
} }
func init() { func init() {
log.SetPrefix("[proxy] ")
log.SetFlags(log.Flags() | log.Lmsgprefix)
executable, err := os.Executable() executable, err := os.Executable()
if err != nil { if err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
path := filepath.Dir(executable) + "/latest.log" path := filepath.Dir(executable) + "/latest.log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil { if err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
go func() { go func() {
@ -38,6 +43,6 @@ func init() {
select {} select {}
}() }()
lw := &LogWriter{f} logWriter = &LogWriter{f}
log.SetOutput(lw) log.SetOutput(logWriter)
} }

View File

@ -17,7 +17,7 @@ func loadPlugins() {
func openPlugins() { func openPlugins() {
executable, err := os.Executable() executable, err := os.Executable()
if err != nil { if err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
path := filepath.Dir(executable) + "/plugins" path := filepath.Dir(executable) + "/plugins"
@ -25,16 +25,16 @@ func openPlugins() {
dir, err := os.ReadDir(path) dir, err := os.ReadDir(path)
if err != nil { if err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
for _, file := range dir { for _, file := range dir {
_, err := plugin.Open(path + "/" + file.Name()) _, err := plugin.Open(path + "/" + file.Name())
if err != nil { if err != nil {
log.Print("{←|⇶} ", err) log.Print(err)
continue continue
} }
} }
log.Print("{←|⇶} load plugins") log.Print("load plugins")
} }

24
run.go
View File

@ -14,7 +14,7 @@ import (
// It blocks forever. // It blocks forever.
func Run() { func Run() {
if err := LoadConfig(); err != nil { if err := LoadConfig(); err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
if !Conf().NoPlugins { if !Conf().NoPlugins {
@ -26,29 +26,29 @@ func Run() {
case "sqlite3": case "sqlite3":
setAuthBackend(authSQLite3{}) setAuthBackend(authSQLite3{})
default: default:
log.Fatal("{←|⇶} invalid auth backend") log.Fatal("invalid auth backend")
} }
go func() { go func() {
if err := telnetServer(); err != nil { if err := telnetServer(); err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
}() }()
addr, err := net.ResolveUDPAddr("udp", Conf().BindAddr) addr, err := net.ResolveUDPAddr("udp", Conf().BindAddr)
if err != nil { if err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
pc, err := net.ListenUDP("udp", addr) pc, err := net.ListenUDP("udp", addr)
if err != nil { if err != nil {
log.Fatal("{←|⇶} ", err) log.Fatal(err)
} }
l := listen(pc) l := listen(pc)
defer l.Close() defer l.Close()
log.Print("{←|⇶} listen ", l.Addr()) log.Println("listen", l.Addr())
go func() { go func() {
sig := make(chan os.Signal, 1) sig := make(chan os.Signal, 1)
@ -59,7 +59,7 @@ func Run() {
if Conf().List.Enable { if Conf().List.Enable {
if err := announce(listRm); err != nil { if err := announce(listRm); err != nil {
log.Print("{←|⇶} ", err) log.Print(err)
} }
} }
@ -83,11 +83,11 @@ func Run() {
cc, err := l.accept() cc, err := l.accept()
if err != nil { if err != nil {
if errors.Is(err, net.ErrClosed) { if errors.Is(err, net.ErrClosed) {
log.Print("{←|⇶} stop listening") log.Print("stop listening")
break break
} }
log.Print("{←|⇶} ", err) log.Print(err)
continue continue
} }
@ -96,21 +96,21 @@ func Run() {
cc.Log("<->", "handshake completed") cc.Log("<->", "handshake completed")
if len(Conf().Servers) == 0 { if len(Conf().Servers) == 0 {
cc.Log("<--", "no servers") cc.Log("<-", "no servers")
cc.Kick("No servers are configured.") cc.Kick("No servers are configured.")
return return
} }
addr, err := net.ResolveUDPAddr("udp", Conf().Servers[0].Addr) addr, err := net.ResolveUDPAddr("udp", Conf().Servers[0].Addr)
if err != nil { if err != nil {
cc.Log("<--", "address resolution fail") cc.Log("<-", "address resolution fail")
cc.Kick("Server address resolution failed.") cc.Kick("Server address resolution failed.")
return return
} }
conn, err := net.DialUDP("udp", nil, addr) conn, err := net.DialUDP("udp", nil, addr)
if err != nil { if err != nil {
cc.Log("<--", "connection fail") cc.Log("<-", "connection fail")
cc.Kick("Server connection failed.") cc.Kick("Server connection failed.")
return return
} }

View File

@ -2,7 +2,6 @@ package proxy
import ( import (
"errors" "errors"
"fmt"
"log" "log"
"net" "net"
"strings" "strings"
@ -20,6 +19,8 @@ type ServerConn struct {
clt *ClientConn clt *ClientConn
mu sync.RWMutex mu sync.RWMutex
logger *log.Logger
cstate clientState cstate clientState
cstateMu sync.RWMutex cstateMu sync.RWMutex
name string name string
@ -71,20 +72,7 @@ func (sc *ServerConn) Init() <-chan struct{} { return sc.initCh }
// Log logs an interaction with the ServerConn. // Log logs an interaction with the ServerConn.
// dir indicates the direction of the interaction. // dir indicates the direction of the interaction.
func (sc *ServerConn) Log(dir string, v ...interface{}) { func (sc *ServerConn) Log(dir string, v ...interface{}) {
if sc.client() != nil { sc.logger.Println(append([]interface{}{dir}, v...)...)
format := "%s {%s}"
format += strings.Repeat(" %v", len(v))
sc.client().Log("", fmt.Sprintf(format, append([]interface{}{
dir,
sc.name,
}, v...)...))
} else {
format := "{←|⇶} %s {%s}"
format += strings.Repeat(" %v", len(v))
log.Printf(format, append([]interface{}{dir, sc.name}, v...)...)
}
} }
func handleSrv(sc *ServerConn) { func handleSrv(sc *ServerConn) {
@ -96,7 +84,7 @@ func handleSrv(sc *ServerConn) {
select { select {
case <-init: case <-init:
case <-time.After(10 * time.Second): case <-time.After(10 * time.Second):
sc.Log("-->", "timeout") sc.Log("->", "timeout")
sc.Close() sc.Close()
} }
}(init) }(init)
@ -146,20 +134,20 @@ func handleSrv(sc *ServerConn) {
break break
} }
sc.Log("<--", err) sc.Log("<-", err)
continue continue
} }
clt := sc.client() clt := sc.client()
if clt == nil { if clt == nil {
sc.Log("<--", "no client") sc.Log("<-", "no client")
continue continue
} }
switch cmd := pkt.Cmd.(type) { switch cmd := pkt.Cmd.(type) {
case *mt.ToCltHello: case *mt.ToCltHello:
if sc.auth.method != 0 { if sc.auth.method != 0 {
sc.Log("<--", "unexpected authentication") sc.Log("<-", "unexpected authentication")
sc.Close() sc.Close()
break break
} }
@ -172,7 +160,7 @@ func handleSrv(sc *ServerConn) {
} }
if cmd.SerializeVer != latestSerializeVer { if cmd.SerializeVer != latestSerializeVer {
sc.Log("<--", "invalid serializeVer") sc.Log("<-", "invalid serializeVer")
break break
} }
@ -180,7 +168,7 @@ func handleSrv(sc *ServerConn) {
case mt.SRP: case mt.SRP:
sc.auth.srpA, sc.auth.a, err = srp.InitiateHandshake() sc.auth.srpA, sc.auth.a, err = srp.InitiateHandshake()
if err != nil { if err != nil {
sc.Log("-->", err) sc.Log("->", err)
break break
} }
@ -191,7 +179,7 @@ func handleSrv(sc *ServerConn) {
case mt.FirstSRP: case mt.FirstSRP:
salt, verifier, err := srp.NewClient([]byte(clt.name), []byte{}) salt, verifier, err := srp.NewClient([]byte(clt.name), []byte{})
if err != nil { if err != nil {
sc.Log("-->", err) sc.Log("->", err)
break break
} }
@ -206,19 +194,19 @@ func handleSrv(sc *ServerConn) {
} }
case *mt.ToCltSRPBytesSaltB: case *mt.ToCltSRPBytesSaltB:
if sc.auth.method != mt.SRP { if sc.auth.method != mt.SRP {
sc.Log("<--", "multiple authentication attempts") sc.Log("<-", "multiple authentication attempts")
break break
} }
sc.auth.srpK, err = srp.CompleteHandshake(sc.auth.srpA, sc.auth.a, []byte(clt.name), []byte{}, cmd.Salt, cmd.B) sc.auth.srpK, err = srp.CompleteHandshake(sc.auth.srpA, sc.auth.a, []byte(clt.name), []byte{}, cmd.Salt, cmd.B)
if err != nil { if err != nil {
sc.Log("-->", err) sc.Log("->", err)
break break
} }
M := srp.ClientProof([]byte(clt.name), cmd.Salt, sc.auth.srpA, cmd.B, sc.auth.srpK) M := srp.ClientProof([]byte(clt.name), cmd.Salt, sc.auth.srpA, cmd.B, sc.auth.srpK)
if M == nil { if M == nil {
sc.Log("<--", "SRP safety check fail") sc.Log("<-", "SRP safety check fail")
break break
} }
@ -226,7 +214,7 @@ func handleSrv(sc *ServerConn) {
M: M, M: M,
}) })
case *mt.ToCltDisco: case *mt.ToCltDisco:
sc.Log("<--", "deny access", cmd) sc.Log("<-", "deny access", cmd)
ack, _ := clt.SendCmd(cmd) ack, _ := clt.SendCmd(cmd)
select { select {
@ -245,9 +233,9 @@ func handleSrv(sc *ServerConn) {
}{} }{}
sc.SendCmd(&mt.ToSrvInit2{Lang: clt.lang}) sc.SendCmd(&mt.ToSrvInit2{Lang: clt.lang})
case *mt.ToCltDenySudoMode: case *mt.ToCltDenySudoMode:
sc.Log("<--", "deny sudo") sc.Log("<-", "deny sudo")
case *mt.ToCltAcceptSudoMode: case *mt.ToCltAcceptSudoMode:
sc.Log("<--", "accept sudo") sc.Log("<-", "accept sudo")
sc.setState(sc.state() + 1) sc.setState(sc.state() + 1)
case *mt.ToCltAnnounceMedia: case *mt.ToCltAnnounceMedia:
sc.SendCmd(&mt.ToSrvReqMedia{}) sc.SendCmd(&mt.ToSrvReqMedia{})

View File

@ -3,11 +3,11 @@ package proxy
import ( import (
"bufio" "bufio"
"errors" "errors"
"fmt"
"io" "io"
"log" "log"
"math" "math"
"net" "net"
"strings"
) )
// A TelnetWriter can be used to print something at the other end // A TelnetWriter can be used to print something at the other end
@ -32,7 +32,7 @@ func telnetServer() error {
} }
defer ln.Close() defer ln.Close()
log.Print("{←|⇶} listen telnet ", ln.Addr()) log.Println("listen telnet", ln.Addr())
for { for {
select { select {
@ -41,7 +41,7 @@ func telnetServer() error {
default: default:
conn, err := ln.Accept() conn, err := ln.Accept()
if err != nil { if err != nil {
log.Print("{←|⇶} ", err) log.Print(err)
continue continue
} }
@ -52,13 +52,9 @@ func telnetServer() error {
func handleTelnet(conn net.Conn) { func handleTelnet(conn net.Conn) {
tlog := func(dir string, v ...interface{}) { tlog := func(dir string, v ...interface{}) {
format := "{%s} %s {←|⇶}" prefix := fmt.Sprintf("[telnet %s] ", conn.RemoteAddr())
format += strings.Repeat(" %v", len(v)) l := log.New(logWriter, prefix, log.LstdFlags|log.Lmsgprefix)
l.Println(append([]interface{}{dir}, v...)...)
log.Printf(format, append([]interface{}{
conn.RemoteAddr(),
dir,
}, v...)...)
} }
tlog("<->", "telnet connect") tlog("<->", "telnet connect")
@ -89,11 +85,11 @@ func handleTelnet(conn net.Conn) {
return return
} }
log.Print("{←|⇶} ", err) log.Print(err)
continue continue
} }
tlog("-->", "telnet command", s) tlog("->", "telnet command", s)
if s == "\\quit" || s == "\\q" { if s == "\\quit" || s == "\\q" {
return return