func (this *ConnectImpl) HandlePacket(packet packet.Packet) (err error) {
	switch packet.Id() {
	case connect.PACKET_KEEPALIVE:
		err = this.Write(packet)
	case connect.PACKET_RESULT:
		packetResult := packet.(*connect.PacketResult)
		err = this.DispatchResult(packetResult.SequenceId, packetResult.StatusCode, packetResult.Result)
	case connect.PACKET_MESSAGE_EVENT:
		this.DispatchEvent("message", WrapEventMessage(packet.(*connect.PacketMessageEvent)))
	case connect.PACKET_REDIRECT_EVENT:
		this.DispatchEvent("redirect", WrapEventRedirect(packet.(*connect.PacketRedirectEvent)))
	case connect.PACKET_SERVER_EVENT:
		this.DispatchEvent("server", WrapEventServer(packet.(*connect.PacketServerEvent)))
	}
	return
}
Esempio n. 2
0
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
}
Esempio n. 3
0
func (this *Session) HandlePacket(packet packet.Packet) (err error) {
	switch packet.Id() {
	case connect.PACKET_KEEPALIVE:
		if this.keepalive == nil {
			this.Close()
			return
		}
		if *this.keepalive != packet.(*connect.PacketKeepalive).Random {
			this.Close()
			return
		}
		this.keepalive = nil
	case connect.PACKET_REQUEST:
		request := packet.(*connect.PacketRequest).Request
		var result connect.Result
		var statusCode uint8
		switch request.Id() {
		case connect.REQUEST_AUTHENTICATE:
			if !this.Authorized() {
				username := request.(*connect.RequestAuthenticate).Username
				var ok bool
				ok, err = this.server.Authenticator().Authenticate(username, request.(*connect.RequestAuthenticate).Password, this.salt)
				if err != nil {
					return
				}
				if ok {
					this.RegisterAuthorized(username)
					fmt.Println("Connect server, authorized:", this.Id(), "ip:", this.RemoteIp())
					result = &connect.ResultAuthenticate{}
					statusCode = connect.STATUS_SUCCESS
				} else {
					fmt.Println("Connect server, failure to authorize:", username, "ip:", this.RemoteIp())
					statusCode = connect.STATUS_ERROR_GENERIC
				}
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_AS_PROXY:
			if this.Authorized() {
				if this.RegisterProxy(request.(*connect.RequestAsProxy).Address, request.(*connect.RequestAsProxy).Port, request.(*connect.RequestAsProxy).Motd, request.(*connect.RequestAsProxy).Version, request.(*connect.RequestAsProxy).Maxplayers) {
					fmt.Println("Connect server, roled as proxy:", this.Id(), "ip:", this.RemoteIp())
					result = &connect.ResultAsProxy{}
					statusCode = connect.STATUS_SUCCESS
				} else {
					statusCode = connect.STATUS_ERROR_GENERIC
				}
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_AS_SERVER:
			if this.Authorized() {
				if this.RegisterServer(request.(*connect.RequestAsServer).Address, request.(*connect.RequestAsServer).Port) {
					fmt.Println("Connect server, roled as server:", this.Id(), "ip:", this.RemoteIp())
					result = &connect.ResultAsServer{this.serverSecurityKey}
					statusCode = connect.STATUS_SUCCESS
				} else {
					statusCode = connect.STATUS_ERROR_GENERIC
				}
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_GET_DETAILS:
			if this.Authorized() {
				networkCache := this.server.NetworkCache()
				result = &connect.ResultGetDetails{networkCache.Address(), networkCache.Port(), networkCache.Motd(), networkCache.Version()}
				statusCode = connect.STATUS_SUCCESS
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_GET_PLAYERS:
			if this.Authorized() {
				networkCache := this.server.NetworkCache()
				players := networkCache.Players()
				if request.(*connect.RequestGetPlayers).List {
					result = &connect.ResultGetPlayers{true, uint16(len(players)), networkCache.MaxPlayers(), players}
				} else {
					result = &connect.ResultGetPlayers{false, uint16(len(players)), networkCache.MaxPlayers(), nil}
				}
				statusCode = connect.STATUS_SUCCESS
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_GET_SALT:
			result = &connect.ResultGetSalt{this.salt}
			statusCode = connect.STATUS_SUCCESS
		case connect.REQUEST_GET_WHOAMI:
			result = &connect.ResultGetWhoami{this.Id()}
			statusCode = connect.STATUS_SUCCESS
		case connect.REQUEST_MESSAGE:
			if this.Authorized() {
				sessionRegistry := this.server.SessionRegistry(AUTHORIZED)
				recipients := request.(*connect.RequestMessage).Recipients
				messagePacket := &connect.PacketMessageEvent{this.Id(), request.(*connect.RequestMessage).Channel, request.(*connect.RequestMessage).Message}
				messageSent := false
				if len(recipients) == 0 {
					for _, recipient := range sessionRegistry.GetAll() {
						recipient.Write(messagePacket)
						messageSent = true
					}
				} else {
					for _, recipientId := range recipients {
						recipient := sessionRegistry.GetById(recipientId)
						if recipient == nil {
							continue
						}
						recipient.Write(messagePacket)
						messageSent = true
					}
				}
				if messageSent {
					result = &connect.ResultMessage{}
					statusCode = connect.STATUS_SUCCESS
				} else {
					statusCode = connect.STATUS_ERROR_GENERIC
				}
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_NOTIFY_PLAYER:
			if this.Authorized() && this.role == ROLE_PROXY {
				add := request.(*connect.RequestNotifyPlayer).Add
				player := request.(*connect.RequestNotifyPlayer).Player
				if add {
					if !this.server.NetworkCache().AddPlayer(player, this) {
						statusCode = connect.STATUS_ERROR_GENERIC
						break
					}
					this.proxyPlayers[player] = true
				} else {
					if _, ok := this.proxyPlayers[player]; ok {
						this.server.NetworkCache().RemovePlayer(player)
						delete(this.proxyPlayers, player)
					}
				}
				result = &connect.ResultNotifyPlayer{}
				statusCode = connect.STATUS_SUCCESS
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		case connect.REQUEST_REDIRECT:
			if this.Authorized() {
				server := request.(*connect.RequestRedirect).Server
				player := request.(*connect.RequestRedirect).Player
				session := this.server.NetworkCache().ProxyByPlayer(player)
				if session == nil {
					statusCode = connect.STATUS_ERROR_GENERIC
					break
				}
				session.Write(&connect.PacketRedirectEvent{server, player})
				result = &connect.ResultRedirect{}
				statusCode = connect.STATUS_SUCCESS
			} else {
				statusCode = connect.STATUS_ERROR_ROLE
			}
		default:
			err = errors.New(fmt.Sprintf("Request Id is not handled by server: %d", request.Id()))
			return
		}
		err = this.Write(&connect.PacketResult{packet.(*connect.PacketRequest).SequenceId, statusCode, result})
	default:
		err = errors.New(fmt.Sprintf("Packet Id is not handled by server: %d", packet.Id()))
	}
	return
}
func (this *SessionOutBridge) HandlePacket(packet packet.Packet) (err error) {
	if !this.session.Authenticated() {
		this.conn.Close()
		return
	}
	switch this.state {
	case STATE_LOGIN:
		if packet.Id() == minecraft.PACKET_CLIENT_LOGIN_SUCCESS {
			this.session.redirectMutex.Lock()
			this.state = STATE_INIT
			this.session.redirecting = true
			this.EnsureCompression()
			if this.session.protocol17 {
				this.pipeline.Replace("registry", minecraft.PlayPacketClientCodec17)
			} else {
				this.pipeline.Replace("registry", minecraft.PlayPacketClientCodec)
			}
		} else if packet.Id() == minecraft.PACKET_CLIENT_LOGIN_DISCONNECT {
			this.session.DisconnectJson(packet.(*minecraft.PacketClientLoginDisconnect).Json)
			this.conn.Close()
		} else if packet.Id() == minecraft.PACKET_CLIENT_LOGIN_SET_COMPRESSION {
			this.SetCompression(packet.(*minecraft.PacketClientLoginSetCompression).Threshold)
		} else {
			if this.session.Initializing() {
				this.session.Disconnect("Error: Outbound Protocol Mismatch")
			}
			this.conn.Close()
		}
	case STATE_INIT:
		if packet.Id() == minecraft.PACKET_CLIENT_PLAYER_POSITION_AND_LOOK {
			this.session.outBridge = this
			this.session.redirecting = false
			this.session.state = STATE_CONNECTED
			this.state = STATE_CONNECTED
			this.session.redirectMutex.Unlock()
		}
		fallthrough
	case STATE_CONNECTED:
		if packet.Id() == minecraft.PACKET_CLIENT_DISCONNECT {
			this.state = STATE_DISCONNECTED
		}
		if this.state == STATE_CONNECTED {
			this.session.redirectMutex.Lock()
			if this.session.outBridge != this {
				this.session.outBridge.EnsureCompression()
				this.conn.Close()
				this.session.redirectMutex.Unlock()
				break
			}
			this.session.redirectMutex.Unlock()
		}
		switch packet.Id() {
		case minecraft.PACKET_CLIENT_JOIN_GAME:
			joinGamePacket := packet.(*minecraft.PacketClientJoinGame)
			if this.session.clientSettings != nil {
				this.Write(this.session.clientSettings)
			}
			this.session.serverEntityId = joinGamePacket.EntityId
			if this.session.state == STATE_INIT {
				this.session.clientEntityId = joinGamePacket.EntityId
			} else {
				var swapDimension int32
				if joinGamePacket.Dimension == 0 {
					swapDimension = 1
				} else {
					swapDimension = 0
				}
				this.session.Write(minecraft.NewPacketClientRespawn(swapDimension, 2, 0, "DEFAULT"))
				this.session.Write(minecraft.NewPacketClientRespawn(int32(joinGamePacket.Dimension), joinGamePacket.Difficulty, joinGamePacket.Gamemode, joinGamePacket.LevelType))
				if len(this.session.playerList) > 0 {
					if this.session.protocol17 {
						for player, _ := range this.session.playerList {
							this.session.Write(minecraft.NewPacketClientPlayerList17Remove(player))
						}
					} else {
						items := make([]minecraft.PacketClientPlayerListItem, 0, len(this.session.playerList))
						for uuidString, _ := range this.session.playerList {
							items = append(items, minecraft.PacketClientPlayerListItem{UUID: uuid.UUID(uuidString)})
						}
						this.session.Write(minecraft.NewPacketClientPlayerList(minecraft.PACKET_CLIENT_PLAYER_LIST_ACTION_REMOVE, items))
					}
					this.session.playerList = make(map[string]struct{})
				}
				if len(this.session.scoreboards) > 0 {
					for scoreboard, _ := range this.session.scoreboards {
						this.session.Write(minecraft.NewPacketClientScoreboardObjectiveRemove(scoreboard))
					}
					this.session.scoreboards = make(map[string]struct{})
				}
				if len(this.session.teams) > 0 {
					for team, _ := range this.session.teams {
						this.session.Write(minecraft.NewPacketClientTeamsRemove(team))
					}
					this.session.teams = make(map[string]struct{})
				}
				if len(this.session.pluginChannels) > 0 {
					channels := make([][]byte, 0, len(this.session.pluginChannels))
					for channel, _ := range this.session.pluginChannels {
						channels = append(channels, []byte(channel))
					}
					this.Write(minecraft.NewPacketServerPluginMessage("REGISTER", bytes.Join(channels, []byte{0})))
				}
				return
			}
		case minecraft.PACKET_CLIENT_PLAYER_LIST:
			if this.session.protocol17 {
				playerListPacket := packet.(*minecraft.PacketClientPlayerList17)
				if playerListPacket.Online {
					this.session.playerList[playerListPacket.Name] = struct{}{}
				} else {
					delete(this.session.playerList, playerListPacket.Name)
				}
			} else {
				playerListPacket := packet.(*minecraft.PacketClientPlayerList)
				if playerListPacket.Action == minecraft.PACKET_CLIENT_PLAYER_LIST_ACTION_ADD {
					for _, item := range playerListPacket.Items {
						this.session.playerList[string(item.UUID)] = struct{}{}
					}
				} else if playerListPacket.Action == minecraft.PACKET_CLIENT_PLAYER_LIST_ACTION_REMOVE {
					for _, item := range playerListPacket.Items {
						delete(this.session.playerList, string(item.UUID))
					}
				}
			}
		case minecraft.PACKET_CLIENT_SCOREBOARD_OBJECTIVE:
			scoreboardPacket := packet.(*minecraft.PacketClientScoreboardObjective)
			if scoreboardPacket.Action == minecraft.PACKET_CLIENT_SCOREBOARD_OBJECTIVE_ACTION_ADD {
				this.session.scoreboards[scoreboardPacket.Name] = struct{}{}
			} else if scoreboardPacket.Action == minecraft.PACKET_CLIENT_SCOREBOARD_OBJECTIVE_ACTION_REMOVE {
				delete(this.session.scoreboards, scoreboardPacket.Name)
			}
		case minecraft.PACKET_CLIENT_TEAMS:
			teamPacket := packet.(*minecraft.PacketClientTeams)
			if teamPacket.Action == minecraft.PACKET_CLIENT_TEAMS_ACTION_ADD {
				this.session.teams[teamPacket.Name] = struct{}{}
			} else if teamPacket.Action == minecraft.PACKET_CLIENT_TEAMS_ACTION_REMOVE {
				delete(this.session.teams, teamPacket.Name)
			}
		case minecraft.PACKET_CLIENT_DISCONNECT:
			this.session.DisconnectJson(packet.(*minecraft.PacketClientDisconnect).Json)
			return
		case minecraft.PACKET_CLIENT_SET_COMPRESSION:
			this.SetCompression(packet.(*minecraft.PacketClientSetCompression).Threshold)
			return
		default:
			if genericPacket, ok := packet.(*minecraft.PacketGeneric); ok {
				genericPacket.SwapEntities(this.session.clientEntityId, this.session.serverEntityId, true, this.session.protocol17)
			}
		}
		this.session.Write(packet)
	}
	return
}
Esempio n. 5
0
func (this *SessionOutBridge) HandlePacket(packet packet.Packet) (err error) {
	this.session.outMutex.Lock()
	defer this.session.outMutex.Unlock()
	if !this.session.Authenticated() {
		this.conn.Close()
		return
	}
	switch this.state {
	case STATE_LOGIN:
		if packet.Id() == minecraft.PACKET_CLIENT_LOGIN_SUCCESS {
			this.state = STATE_INIT
			this.session.redirecting = true
			this.codec.SetEncodeCodec(minecraft.PlayPacketServerCodec)
			this.codec.SetDecodeCodec(minecraft.PlayPacketClientCodec)
		} else if packet.Id() == minecraft.PACKET_CLIENT_LOGIN_DISCONNECT {
			this.session.DisconnectRaw(packet.(*minecraft.PacketClientLoginDisconnect).Json)
			this.conn.Close()
		} else {
			if this.session.Initializing() {
				this.session.Disconnect("Error: Outbound Protocol Mismatch")
			}
			this.conn.Close()
		}
	case STATE_INIT:
		if packet.Id() == 0x08 {
			oldOutBridge := this.session.outBridge
			if oldOutBridge != nil {
				oldOutBridge.conn.Close()
			}
			this.session.outBridge = this
			this.session.redirecting = false
			this.session.state = STATE_CONNECTED
			this.state = STATE_CONNECTED
		}
		fallthrough
	case STATE_CONNECTED:
		if packet.Id() == minecraft.PACKET_CLIENT_DISCONNECT {
			this.state = STATE_DISCONNECTED
		}
		if this.session.outBridge == this && this.session.redirecting {
			break
		}
		switch packet.Id() {
		case minecraft.PACKET_CLIENT_JOIN_GAME:
			joinGamePacket := packet.(*minecraft.PacketClientJoinGame)
			if this.session.clientSettings != nil {
				this.Write(this.session.clientSettings)
			}
			this.session.serverEntityId = joinGamePacket.EntityId
			if this.session.state == STATE_INIT {
				this.session.clientEntityId = joinGamePacket.EntityId
			} else {
				var swapDimension int32
				if joinGamePacket.Dimension == 0 {
					swapDimension = 1
				} else {
					swapDimension = 0
				}
				this.session.Write(&minecraft.PacketClientRespawn{swapDimension, 2, 0, "DEFAULT"})
				this.session.Write(&minecraft.PacketClientRespawn{int32(joinGamePacket.Dimension), joinGamePacket.Difficulty, joinGamePacket.Gamemode, joinGamePacket.LevelType})
				for player, _ := range this.session.playerList {
					this.session.Write(&minecraft.PacketClientPlayerListItem{player, false, 0})
				}
				this.session.playerList = make(map[string]bool)
				for scoreboard, _ := range this.session.scoreboards {
					this.session.Write(&minecraft.PacketClientScoreboardObjective{scoreboard, "", 1})
				}
				this.session.scoreboards = make(map[string]bool)
				for team, _ := range this.session.teams {
					this.session.Write(&minecraft.PacketClientTeams{team, 1, "", "", "", 0, nil})
				}
				this.session.teams = make(map[string]bool)
				return
			}
		case minecraft.PACKET_CLIENT_PLAYER_LIST_ITEM:
			playerListPacket := packet.(*minecraft.PacketClientPlayerListItem)
			if playerListPacket.Online {
				this.session.playerList[playerListPacket.Name] = true
			} else {
				delete(this.session.playerList, playerListPacket.Name)
			}
		case minecraft.PACKET_CLIENT_SCOREBOARD_OBJECTIVE:
			scoreboardPacket := packet.(*minecraft.PacketClientScoreboardObjective)
			if scoreboardPacket.Action == 0 {
				this.session.scoreboards[scoreboardPacket.Name] = true
			} else if scoreboardPacket.Action == 1 {
				delete(this.session.scoreboards, scoreboardPacket.Name)
			}
		case minecraft.PACKET_CLIENT_TEAMS:
			teamPacket := packet.(*minecraft.PacketClientTeams)
			if teamPacket.Action == 0 {
				this.session.teams[teamPacket.Name] = true
			} else if teamPacket.Action == 1 {
				delete(this.session.teams, teamPacket.Name)
			}
		case minecraft.PACKET_CLIENT_DISCONNECT:
			this.session.DisconnectRaw(packet.(*minecraft.PacketClientDisconnect).Json)
			return
		default:
			if genericPacket, ok := packet.(*minecraft.PacketGeneric); ok {
				genericPacket.SwapEntities(this.session.clientEntityId, this.session.serverEntityId, true)
			}
		}
		this.session.Write(packet)
	}
	return
}
Esempio n. 6
0
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
}