Add some logging for suspicious HitMessages (#459)

* Add some logging for suspicious HitMessages

* Add HitPositionDiscrepancyThreshold config settings

* Add hit position discrepancy check to LashMessage & SplashHitMessage

* Whitespace
This commit is contained in:
Mazo 2020-05-26 21:17:19 +01:00 committed by GitHub
parent e51e970e51
commit 11a01b038f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 5 deletions

View file

@ -12,14 +12,14 @@ import scodec.codecs._
* @param player na * @param player na
* @param victim na * @param victim na
* @param bullet na * @param bullet na
* @param pos na * @param hit_pos na
* @param unk1 na * @param unk1 na
*/ */
final case class LashMessage(seq_time : Int, final case class LashMessage(seq_time : Int,
player : PlanetSideGUID, player : PlanetSideGUID,
victim : PlanetSideGUID, victim : PlanetSideGUID,
bullet : PlanetSideGUID, bullet : PlanetSideGUID,
pos : Vector3, hit_pos : Vector3,
unk1 : Int) unk1 : Int)
extends PlanetSideGamePacket { extends PlanetSideGamePacket {
type Packet = LashMessage type Packet = LashMessage
@ -33,7 +33,7 @@ object LashMessage extends Marshallable[LashMessage] {
("player" | PlanetSideGUID.codec) :: ("player" | PlanetSideGUID.codec) ::
("victim" | PlanetSideGUID.codec) :: ("victim" | PlanetSideGUID.codec) ::
("bullet" | PlanetSideGUID.codec) :: ("bullet" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) :: ("hit_pos" | Vector3.codec_pos) ::
("unk1" | uintL(3)) ("unk1" | uintL(3))
).as[LashMessage] ).as[LashMessage]
} }

View file

@ -248,3 +248,12 @@ NetSim.ReorderTime = 150 milliseconds
# yes - (Enabled) # yes - (Enabled)
Active = no Active = no
[antihack]
# HitPositionDiscrepancyThreshold (int)
# Description: The distance (squared) threshold that triggers if the reported hit location of a shot does not match the object being hit's location on the server
# Range: [1, 1000000]
# Default: 10000 (sqrt 10000 = ~100 ingame units)
HitPositionDiscrepancyThreshold = 10000

View file

@ -45,6 +45,9 @@ object WorldConfig extends ConfigParser {
), ),
ConfigSection("kamon", ConfigSection("kamon",
ConfigEntryBool("Active", false) ConfigEntryBool("Active", false)
),
ConfigSection("antihack",
ConfigEntryInt("HitPositionDiscrepancyThreshold", 10000, Constraints.min(1), Constraints.max(1000000))
) )
) )

View file

@ -5,7 +5,10 @@ import com.github.mauricio.async.db.general.ArrayRowData
import com.github.mauricio.async.db.{Connection, QueryResult} import com.github.mauricio.async.db.{Connection, QueryResult}
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import net.psforever.WorldConfig
import org.log4s.{Logger, MDC} import org.log4s.{Logger, MDC}
import scala.annotation.{switch, tailrec} import scala.annotation.{switch, tailrec}
import scala.collection.mutable.LongMap import scala.collection.mutable.LongMap
import scala.concurrent.{Await, Future, Promise} import scala.concurrent.{Await, Future, Promise}
@ -6213,6 +6216,7 @@ class WorldSessionActor extends Actor
case Some(hitInfo) => case Some(hitInfo) =>
ValidObject(hitInfo.hitobject_guid) match { ValidObject(hitInfo.hitobject_guid) match {
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) => case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
CheckForHitPositionDiscrepancy(projectile_guid, hitInfo.hit_pos, target)
Some((target, hitInfo.shot_origin, hitInfo.hit_pos)) Some((target, hitInfo.shot_origin, hitInfo.hit_pos))
case _ => case _ =>
None None
@ -6238,6 +6242,7 @@ class WorldSessionActor extends Actor
//direct_victim_uid //direct_victim_uid
ValidObject(direct_victim_uid) match { ValidObject(direct_victim_uid) match {
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) => case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, target.Position) match { ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, target.Position) match {
case Some(projectile) => case Some(projectile) =>
HandleDealingDamage(target, projectile) HandleDealingDamage(target, projectile)
@ -6249,6 +6254,7 @@ class WorldSessionActor extends Actor
targets.foreach(elem => { targets.foreach(elem => {
ValidObject(elem.uid) match { ValidObject(elem.uid) match {
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) => case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, explosion_pos) match { ResolveProjectileEntry(projectile, ProjectileResolution.Splash, target, explosion_pos) match {
case Some(projectile) => case Some(projectile) =>
HandleDealingDamage(target, projectile) HandleDealingDamage(target, projectile)
@ -6270,11 +6276,12 @@ class WorldSessionActor extends Actor
case None => ; case None => ;
} }
case msg @ LashMessage(seq_time, killer_guid, victim_guid, projectile_guid, pos, unk1) => case msg @ LashMessage(seq_time, killer_guid, victim_guid, projectile_guid, hit_pos, unk1) =>
log.info(s"Lash: $msg") log.info(s"Lash: $msg")
ValidObject(victim_guid) match { ValidObject(victim_guid) match {
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) => case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Lash, target, pos) match { CheckForHitPositionDiscrepancy(projectile_guid, hit_pos, target)
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Lash, target, hit_pos) match {
case Some(projectile) => case Some(projectile) =>
HandleDealingDamage(target, projectile) HandleDealingDamage(target, projectile)
case None => ; case None => ;
@ -11397,6 +11404,14 @@ class WorldSessionActor extends Actor
} }
} }
def CheckForHitPositionDiscrepancy(projectile_guid: PlanetSideGUID, hitPos : Vector3, target : PlanetSideGameObject with FactionAffinity with Vitality): Unit = {
val hitPositionDiscrepancy = Vector3.DistanceSquared(hitPos, target.Position)
if(hitPositionDiscrepancy > WorldConfig.Get[Int]("antihack.HitPositionDiscrepancyThreshold")) {
// If the target position on the server does not match the position where the projectile landed within reason there may be foul play
log.warn(s"Shot guid ${projectile_guid} has hit location discrepancy with target location. Target: ${target.Position} Reported: ${hitPos}, Distance: ${hitPositionDiscrepancy} / ${math.sqrt(hitPositionDiscrepancy).toFloat}; suspect")
}
}
def failWithError(error : String) = { def failWithError(error : String) = {
log.error(error) log.error(error)
sendResponse(ConnectionClose()) sendResponse(ConnectionClose())