func RPCAuthenticateWithKeyMessage(conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData) error { // Unmarshal the data msg := new(protocol.AuthenticateWithKeyMessage) err := proto.Unmarshal(packet_data.Content, msg) if err != nil { return err } // Generate a new connection-id based npid npid := structs.IdToNpid(connection_data.ConnectionId) // Fill in the connection data connection_data.Authenticated = true connection_data.IsServer = true connection_data.Token = "" connection_data.Npid = npid // Add connection to the storage storage.SetServerConnection(npid, connection_data) // Reply with the data return reply.Reply(conn, packet_data.Header.Id, &protocol.AuthenticateResultMessage{ Result: proto.Int32(0), Npid: proto.Uint64(npid), SessionToken: []byte(""), }) }
func HandleCI2( conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData, stringParts []string, ) error { if len(stringParts) != 2 { return nil } // I assume that's the classic anticheat // I have no idea if it is supposed to work, but I did it reason, err := strconv.Atoi(stringParts[1]) if err != nil { return err } if reason == 50001 { connection_data.LastCI = time.Now() } if connection_data.IsUnclean { return nil } connection_data.IsUnclean = true // Write to database err = environment.Env.Database.Query(` INSERT INTO misago_ban( test, ban, reason_user, expires ) VALUES( ?, ?, ?, ? )`, 0, connection_data.Username, "Cheat detected ("+stringParts[1]+")", time.Now().Add(time.Hour*24*14)).Run() if err != nil { return err } logger.Info(connection_data.Npid, " marked unclean for ", reason) if connection_data.ServerId != 0 { return utils.KickUser(connection_data.ServerId, connection_data.Npid, int64(reason)) } return nil }
func handlePortAnnounced( conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData, stringParts []string, ) error { connection_data.ServerAddr = structs.StripPort(conn.RemoteAddr().String()) + ":" + stringParts[1] return nil }
func HandleCI25( conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData, stringParts []string, ) error { // Parse the token detection_id, guid, err := parseToken25(stringParts) if err != nil { return err } logger.Infof("DETECTION FROM %s: %d", connection_data.Username, detection_id) // We already know that the user is unclean, don't waste time handling it. if connection_data.IsUnclean { return nil } // check the hwid for bans if isHWIDBanned(guid) { detection_id = 10100 } // If reason equals NOT_DETECTED, then it's a check if detection_id == NOT_DETECTED || detection_id == 41009 { // Client is checked, allow it to connect connection_data.LastCI = time.Now() // Append the GUID err = AppendHWID(guid, structs.NpidToId(connection_data.Npid), false) if err != nil { return err } } else { // Set the connection to unclean connection_data.IsUnclean = true // Append the GUID err = AppendHWID(guid, structs.NpidToId(connection_data.Npid), true) if err != nil { return err } if environment.Env.Config.NP.AnticheatInstant { // Ban that user err = utils.BanUser(connection_data.Username, detection_id, time.Hour*24*14) if err != nil { return err } // Kick him! if connection_data.ServerId != 0 { err = utils.KickUser(connection_data.ServerId, connection_data.Npid, detection_id) } } else { // Add a delayed ban err = utils.AddDelayedBan(connection_data.Npid, detection_id, guid) if err != nil { return err } } } return nil }
func (n *NPServer) HandleConnection(conn net.Conn) { // Close the connection after it ends its execution defer conn.Close() // This is the place where you should put stuff to be executed for the "connection" event // The below code is the most non-thread-safe way to create such identifiers // If we get enough load, servers can f**k up TotalConnections++ LastCid++ cid := LastCid // Here comes a struct for connection data, that we pass over to handlers connection_data := new(structs.ConnData) connection_data.Authenticated = false // Because we don't want session stealing connection_data.ConnectionId = cid // Connection ID is mainly used in servers connection_data.PresenceData = make(map[string]string) // If we don't init it here, it'll panic later connection_data.Connection = conn connection_data.Valid = true for { // Set timeout conn.SetReadDeadline(time.Now().Add(60 * time.Second)) // First 16 bytes are defined in the structs subpackage // It consists of four, 4-byte Little Endian unsigned 32bit integers // in the following order: signature, length, type, id headerBytes := make([]byte, 16) _, err := conn.Read(headerBytes) if err != nil { if err != io.EOF { logger.Warningf("Error while reading the header; %s", err) } break } // Initialize a bytes mapper buf := bytes.NewReader(headerBytes) // Map data to the struct var packet_header structs.PacketHeader err = binary.Read(buf, binary.LittleEndian, &packet_header) if err != nil { logger.Warningf("Error while mapping packet_header to struct; %s", err) continue } // Signature check if packet_header.Signature != packet_signature { logger.Warningf( "Signature doesn't match (from %s), received 0x%X", conn.RemoteAddr().String(), packet_header.Signature, ) continue } // Length from the packet_header specifies how many of the next bytes are the content // Pass it over to the handlers which will decode it using protobuf contentBytes := make([]byte, packet_header.Length) // Set timeout conn.SetReadDeadline(time.Now().Add(60 * time.Second)) // Read the body _, err = io.ReadFull(conn, contentBytes) if err != nil { logger.Warningf("Error while reading; %s", err) break } // Log that we are parsing a RPC message logger.Debugf("Received message %d (ID: %d) from %s", packet_header.Type, packet_header.Id, structs.StripPort(conn.RemoteAddr().String())) // Generate a new PacketData struct packet_data := new(structs.PacketData) packet_data.Header = packet_header packet_data.Content = contentBytes // Pass it to the handlers. Not the best idea to do it using params, we should use // a struct, so we will easily be able to inject more variables. err = HandleMessage(conn, connection_data, packet_data) if err != nil { logger.Warningf("Error while handling message %d from %s; %s", packet_data.Header.Id, conn.RemoteAddr().String(), err) } } if connection_data.Authenticated { if connection_data.IsServer { storage.DeleteServerConnection(connection_data.Npid) } else { storage.DeleteClientConnection(connection_data.Npid) } } // I guess that count is going to be used by the web API TotalConnections-- connection_data.Valid = false }
func RPCAuthenticateWithTokenMessage(conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData) error { // Unmarshal the data msg := new(protocol.AuthenticateWithTokenMessage) err := proto.Unmarshal(packet_data.Content, msg) if err != nil { return err } // Split the token token := string(msg.Token) parts := strings.Split(token, ":") // uid is the first part id, err := strconv.Atoi(parts[0]) if err != nil { return err } // Convert it to the Npid npid := structs.IdToNpid(id) // Set connection data connection_data.Id = id connection_data.Npid = npid connection_data.Token = token // Verify! sess_string, err := environment.Env.Redis.Get("session:" + token).Result() if err != nil { return err } // Format is: ip;rank;username sess_parts := strings.Split(sess_string, ";") // Verify that user has the same IP as the one used to log in if sess_parts[0] != structs.StripPort(conn.RemoteAddr().String()) { return WrongIPAddress } // Get the rank id and save it in the session connection_data.RankId, err = strconv.Atoi(sess_parts[1]) if err != nil { return err } // Authenticate the session connection_data.Authenticated = true connection_data.Username = sess_parts[2] // Add connection to the storage storage.SetClientConnection(npid, connection_data) // Return a response err = reply.Reply(conn, packet_data.Header.Id, &protocol.AuthenticateResultMessage{ Result: proto.Int32(0), Npid: &npid, SessionToken: msg.Token, }) if err != nil { return err } // No idea what this thing is supposed to do time.AfterFunc(time.Millisecond*900, func() { err = reply.Reply(conn, 0, &protocol.AuthenticateExternalStatusMessage{ Status: proto.Int32(0), }) if err != nil { logger.Warning(err) } }) return nil }