func (this *Session) SetAuthenticated(result bool) { if !result { this.Disconnect("Error: Authentication to Minecraft.net Failed") return } if this.server.SessionRegistry.HasName(this.name) { this.Disconnect(minecraft.Colorize(this.server.localizer.LocaleLoggedIn())) return } if this.server.MaxPlayers() > 1 && this.server.SessionRegistry.Len() >= int(this.server.MaxPlayers()) { this.Disconnect(minecraft.Colorize(this.server.localizer.LocaleFull())) return } servers := this.server.router.Route(this.serverAddress) activeServers := []string{} for _, serverName := range servers { if !this.server.connect.HasServer(serverName) { continue } activeServers = append(activeServers, serverName) } if len(activeServers) == 0 { this.Disconnect(minecraft.Colorize(this.server.localizer.LocaleOffline())) return } serverName := activeServers[RandomInt(len(activeServers))] server := this.server.connect.Server(serverName) if server == nil { this.Disconnect("Error: Outbound Server Mismatch: " + serverName) return } addResult := this.server.connect.AddLocalPlayer(this.name) if addResult == 0 { this.Disconnect(minecraft.Colorize(this.server.localizer.LocaleLoggedIn())) return } else if addResult == -1 { this.Disconnect(minecraft.Colorize(this.server.localizer.LocaleLoggedIn())) return } this.state = STATE_INIT if this.protocolVersion >= 5 { this.Write(minecraft.NewPacketClientLoginSuccess(FormatUUID(this.profile.Id), this.name)) } else { this.Write(minecraft.NewPacketClientLoginSuccess(this.profile.Id, this.name)) } if this.protocol17 { this.pipeline.Replace("registry", minecraft.PlayPacketServerCodec17) } else { this.pipeline.Replace("registry", minecraft.PlayPacketServerCodec) } this.server.SessionRegistry.Register(this) this.Redirect(server) }
func (this *Session) SetAuthenticated(result bool) { if !result { this.Disconnect("Error: Authentication to Minecraft.net Failed") return } if this.server.SessionRegistry().HasName(this.name) { this.Disconnect(minecraft.Colorize(this.server.Localizer().LocaleLoggedIn())) return } if this.server.MaxPlayers() > 1 && this.server.SessionRegistry().Len() >= int(this.server.MaxPlayers()) { this.Disconnect(minecraft.Colorize(this.server.Localizer().LocaleFull())) return } servers := this.server.Router().Route(this.serverAddress) for _, serverName := range servers { if this.server.Connect().HasServer(serverName) { continue } for i, otherServerName := range servers { if otherServerName != serverName { continue } servers = append(servers[:i], servers[i+1:]...) break } } if len(servers) == 0 { this.Disconnect(minecraft.Colorize(this.server.Localizer().LocaleOffline())) return } server := this.server.Connect().Server(servers[RandomInt(len(servers))]) addResult := this.server.Connect().AddLocalPlayer(this.name) if addResult == 0 { this.Disconnect(minecraft.Colorize(this.server.Localizer().LocaleLoggedIn())) return } else if addResult == -1 { this.Disconnect(minecraft.Colorize(this.server.Localizer().LocaleLoggedIn())) return } this.state = STATE_INIT this.Write(&minecraft.PacketClientLoginSuccess{this.uuid, this.name}) this.codec.SetEncodeCodec(minecraft.PlayPacketClientCodec) this.codec.SetDecodeCodec(minecraft.PlayPacketServerCodec) this.server.SessionRegistry().Register(this) this.Redirect(server) }
func (this *SessionOutBridge) ErrorCaught(err error) { if this.state == STATE_INIT { this.session.redirecting = false } if this.state != STATE_DISCONNECTED && this.session.outBridge == this { this.session.Disconnect(minecraft.Colorize(this.session.server.Localizer().LocaleLostConn())) } this.session = nil this.server = nil this.state = STATE_DISCONNECTED this.conn.Close() }
func (this *SessionOutBridge) ErrorCaught(err error) { this.session.activeServersLock.Lock() delete(this.session.activeServers, this.server.Name) this.session.activeServersLock.Unlock() if this.state == STATE_INIT { this.session.redirecting = false this.session.redirectMutex.Unlock() } this.disconnectErr = err if this.state != STATE_DISCONNECTED && this.session.outBridge == this { this.session.Disconnect(minecraft.Colorize(this.session.server.localizer.LocaleLostConn())) } this.session = nil this.server = nil this.state = STATE_DISCONNECTED this.conn.Close() }
func (this *Session) HandlePacket(packet packet.Packet) (err error) { switch this.state { case STATE_DISCONNECTED: if packet.Id() == minecraft.PACKET_SERVER_HANDSHAKE { handshakePacket := packet.(*minecraft.PacketServerHandshake) this.protocolVersion = handshakePacket.ProtocolVersion this.serverAddress = handshakePacket.ServerAddress supportedVersion := false for _, version := range minecraft.Versions { if version != this.protocolVersion { continue } supportedVersion = true break } if handshakePacket.State == 1 { if !supportedVersion { this.protocolVersion = minecraft.Versions[0] } this.pipeline.Replace("registry", minecraft.StatusPacketServerCodec) this.state = STATE_STATUS } else if handshakePacket.State == 2 { if !supportedVersion { err = errors.New("Protocol version does not match") return } this.protocol17 = this.protocolVersion < minecraft.Versions[0] if this.protocol17 { this.pipeline.Replace("registry", minecraft.LoginPacketServerCodec17) } else { this.pipeline.Replace("registry", minecraft.LoginPacketServerCodec) } this.state = STATE_LOGIN } else { err = errors.New("Unexpected state") return } } else { err = errors.New("Unexpected packet") return } case STATE_STATUS: if packet.Id() == minecraft.PACKET_SERVER_STATUS_REQUEST { samplePath := this.server.router.RouteSample(this.serverAddress) sampleTxt, sampleErr := ioutil.ReadFile(samplePath) sample := make([]map[string]interface{}, 0) if sampleErr == nil { lines := strings.Split(string(sampleTxt), "\n") for _, line := range lines { line = strings.Replace(line, "\r", "", -1) if len(strings.TrimSpace(line)) == 0 { continue } entry := make(map[string]interface{}) entry["name"] = minecraft.Colorize(line) entry["id"] = "00000000-0000-0000-0000-000000000000" sample = append(sample, entry) } } icons := this.server.router.RouteIcons(this.serverAddress) iconPath := icons[RandomInt(len(icons))] icon, iconErr := ioutil.ReadFile(iconPath) var iconString string if iconErr == nil { iconString = "data:image/png;base64," + base64.StdEncoding.EncodeToString(icon) } version := make(map[string]interface{}) version["name"] = minecraft.STRING_VERSION version["protocol"] = this.protocolVersion players := make(map[string]interface{}) if this.server.SyncMaxPlayers() { players["max"] = this.server.connect.MaxPlayers() } else { players["max"] = this.server.MaxPlayers() } players["online"] = this.server.connect.Players() players["sample"] = sample description := make(map[string]interface{}) motds := this.server.router.RouteMotds(this.serverAddress) motd := motds[RandomInt(len(motds))] description["text"] = minecraft.Colorize(motd) response := make(map[string]interface{}) response["version"] = version response["players"] = players response["description"] = description if iconString != "" { response["favicon"] = iconString } var marshalled []byte marshalled, err = json.Marshal(response) if err != nil { return } err = this.Write(minecraft.NewPacketClientStatusResponse(string(marshalled))) if err != nil { return } this.state = STATE_STATUS_PING } else { err = errors.New("Unexpected packet") return } case STATE_STATUS_PING: if packet.Id() == minecraft.PACKET_SERVER_STATUS_PING { err = this.Write(minecraft.NewPacketClientStatusPing(packet.(*minecraft.PacketServerStatusPing).Time)) if err != nil { return } this.conn.Close() } else { err = errors.New("Unexpected packet") return } case STATE_LOGIN: if packet.Id() == minecraft.PACKET_SERVER_LOGIN_START { this.name = packet.(*minecraft.PacketServerLoginStart).Name if this.server.Authenticate() { this.serverId, err = GenSalt() if err != nil { return } this.publicKey, err = x509.MarshalPKIXPublicKey(&this.server.privateKey.PublicKey) if err != nil { return } this.verifyToken, err = RandomBytes(4) if err != nil { return } err = this.Write(minecraft.NewPacketClientLoginEncryptRequest(this.serverId, this.publicKey, this.verifyToken)) if err != nil { return } this.state = STATE_LOGIN_ENCRYPT } else { this.profile = auth.GameProfile{ Id: GenNameUUID("OfflinePlayer:" + this.name), Properties: make([]auth.GameProfileProperty, 0), } this.SetAuthenticated(true) } } else { err = errors.New("Unexpected packet") return } case STATE_LOGIN_ENCRYPT: if packet.Id() == minecraft.PACKET_SERVER_LOGIN_ENCRYPT_RESPONSE { loginEncryptResponsePacket := packet.(*minecraft.PacketServerLoginEncryptResponse) var sharedSecret []byte sharedSecret, err = rsa.DecryptPKCS1v15(rand.Reader, this.server.privateKey, loginEncryptResponsePacket.SharedSecret) if err != nil { return } var verifyToken []byte verifyToken, err = rsa.DecryptPKCS1v15(rand.Reader, this.server.privateKey, loginEncryptResponsePacket.VerifyToken) if err != nil { return } if bytes.Compare(this.verifyToken, verifyToken) != 0 { err = errors.New("Verify token does not match") return } err = this.SetEncryption(sharedSecret) if err != nil { return } var authErr error this.profile, authErr = auth.Authenticate(this.name, this.serverId, sharedSecret, this.publicKey) if authErr != nil { this.SetAuthenticated(false) fmt.Println("Proxy server, failed to authorize:", this.name, "ip:", this.remoteIp, "err:", authErr) } else { this.SetAuthenticated(true) fmt.Println("Proxy server, authorized:", this.name, "ip:", this.remoteIp) } } else { err = errors.New("Unexpected packet") return } case STATE_CONNECTED: if packet.Id() == minecraft.PACKET_SERVER_CLIENT_SETTINGS { this.clientSettings = packet } if packet.Id() == minecraft.PACKET_SERVER_PLUGIN_MESSAGE { pluginMessagePacket := packet.(*minecraft.PacketServerPluginMessage) if pluginMessagePacket.Channel == "REGISTER" { for _, channelBytes := range bytes.Split(pluginMessagePacket.Data[:], []byte{0}) { channel := string(channelBytes) if _, ok := this.pluginChannels[channel]; ok { continue } if len(this.pluginChannels) >= 128 { break } this.pluginChannels[channel] = struct{}{} } } else if pluginMessagePacket.Channel == "UNREGISTER" { for _, channelBytes := range bytes.Split(pluginMessagePacket.Data[:], []byte{0}) { channel := string(channelBytes) delete(this.pluginChannels, channel) } } } if this.redirecting { break } if genericPacket, ok := packet.(*minecraft.PacketGeneric); ok { genericPacket.SwapEntities(this.clientEntityId, this.serverEntityId, false, this.protocol17) } this.outBridge.Write(packet) } return }
func (this *Session) HandlePacket(packet packet.Packet) (err error) { switch this.state { case STATE_DISCONNECTED: if packet.Id() == minecraft.PACKET_SERVER_HANDSHAKE { handshakePacket := packet.(*minecraft.PacketServerHandshake) this.serverAddress = handshakePacket.ServerAddress if handshakePacket.State == 1 { this.codec.SetEncodeCodec(minecraft.StatusPacketClientCodec) this.codec.SetDecodeCodec(minecraft.StatusPacketServerCodec) this.state = STATE_STATUS } else if handshakePacket.State == 2 { if handshakePacket.ProtocolVersion != minecraft.VERSION { err = errors.New("Protocol version does not match") return } this.codec.SetEncodeCodec(minecraft.LoginPacketClientCodec) this.codec.SetDecodeCodec(minecraft.LoginPacketServerCodec) this.state = STATE_LOGIN } else { err = errors.New("Unexpected state") return } } else { err = errors.New("Unexpected packet") return } case STATE_STATUS: if packet.Id() == minecraft.PACKET_SERVER_STATUS_REQUEST { favicon, faviconErr := ioutil.ReadFile("server-icon.png") var faviconString string if faviconErr == nil { faviconString = "data:image/png;base64," + base64.StdEncoding.EncodeToString(favicon) } version := make(map[string]interface{}) version["name"] = minecraft.STRING_VERSION version["protocol"] = minecraft.VERSION players := make(map[string]interface{}) players["max"] = this.server.Connect().MaxPlayers() players["online"] = this.server.Connect().Players() description := make(map[string]interface{}) description["text"] = minecraft.Colorize(this.server.Router().RouteMotd(this.serverAddress)) response := make(map[string]interface{}) response["version"] = version response["players"] = players response["description"] = description if faviconString != "" { response["favicon"] = faviconString } var marshalled []byte marshalled, err = json.Marshal(response) if err != nil { return } err = this.Write(&minecraft.PacketClientStatusResponse{string(marshalled)}) if err != nil { return } this.state = STATE_STATUS_PING } else { err = errors.New("Unexpected packet") return } case STATE_STATUS_PING: if packet.Id() == minecraft.PACKET_SERVER_STATUS_PING { err = this.Write(&minecraft.PacketClientStatusPing{packet.(*minecraft.PacketServerStatusPing).Time}) if err != nil { return } this.conn.Close() } else { err = errors.New("Unexpected packet") return } case STATE_LOGIN: if packet.Id() == minecraft.PACKET_SERVER_LOGIN_START { this.name = packet.(*minecraft.PacketServerLoginStart).Name if this.server.Authenticate() { this.serverId, err = GenSalt() if err != nil { return } this.publicKey, err = x509.MarshalPKIXPublicKey(&this.server.PrivateKey().PublicKey) if err != nil { return } this.verifyToken, err = RandomBytes(4) if err != nil { return } err = this.Write(&minecraft.PacketClientLoginEncryptRequest{this.serverId, this.publicKey, this.verifyToken}) if err != nil { return } this.state = STATE_LOGIN_ENCRYPT } else { this.uuid = GenNameUUID("OfflinePlayer:" + this.name) this.SetAuthenticated(true) } } else { err = errors.New("Unexpected packet") return } case STATE_LOGIN_ENCRYPT: if packet.Id() == minecraft.PACKET_SERVER_LOGIN_ENCRYPT_RESPONSE { loginEncryptResponsePacket := packet.(*minecraft.PacketServerLoginEncryptResponse) var sharedSecret []byte sharedSecret, err = rsa.DecryptPKCS1v15(rand.Reader, this.server.PrivateKey(), loginEncryptResponsePacket.SharedSecret) if err != nil { return } var verifyToken []byte verifyToken, err = rsa.DecryptPKCS1v15(rand.Reader, this.server.PrivateKey(), loginEncryptResponsePacket.VerifyToken) if err != nil { return } if bytes.Compare(this.verifyToken, verifyToken) != 0 { err = errors.New("Verify token does not match") return } var block cipher.Block block, err = aes.NewCipher(sharedSecret) if err != nil { return } this.connCodec.SetReader(&cipher.StreamReader{ R: this.connCodec.Reader(), S: minecraft.NewCFB8Decrypter(block, sharedSecret), }) this.connCodec.SetWriter(&cipher.StreamWriter{ W: this.connCodec.Writer(), S: minecraft.NewCFB8Encrypter(block, sharedSecret), }) var authErr error this.uuid, authErr = auth.Authenticate(this.name, this.serverId, sharedSecret, this.publicKey) if authErr != nil { this.SetAuthenticated(false) fmt.Println("Proxy server, failed to authorize:", this.name, "ip:", this.RemoteIp(), "err:", authErr) } else { this.SetAuthenticated(true) fmt.Println("Proxy server, authorized:", this.name, "ip:", this.RemoteIp()) } } else { err = errors.New("Unexpected packet") return } case STATE_CONNECTED: if packet.Id() == minecraft.PACKET_SERVER_CLIENT_SETTINGS { this.clientSettings = packet } if this.redirecting { break } if genericPacket, ok := packet.(*minecraft.PacketGeneric); ok { genericPacket.SwapEntities(this.clientEntityId, this.serverEntityId, false) } this.outBridge.Write(packet) } return }