Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active September 6, 2015 19:22
Show Gist options
  • Save dacr/6a449c38b76c1d76eda2 to your computer and use it in GitHub Desktop.
Save dacr/6a449c38b76c1d76eda2 to your computer and use it in GitHub Desktop.
Quick hack to automatically ip geoloc people who tried to get access to your server (using SSH)
#!/bin/sh
exec scala -nc "$0" "$@"
!#
import scala.io._
import java.io._
import scala.util.matching._
val logfiles=if (args.size==0) List("/var/log/auth.log") else args.toList
val failRE="""^(\w+\s+\d+\s+\d{2}:\d{2}:\d{2}).*: Failed password for(?: invalid user)? (\w+) from ([.0-9A-Fa-f:]+) port.*""".r
val jstrRE=""""(\w+)":"([^"]+)"""".r
val jnumRE=""""(\w+)":([.0-9]+)""".r
val logdatefmt = new java.text.SimpleDateFormat("MMM d HH:mm:ss")
def inputStream(filename:String): InputStream = {
val input = new FileInputStream(filename)
filename.toLowerCase match {
case r if r.endsWith(".gz") => new java.util.zip.GZIPInputStream(input)
case _ => input
}
}
case class AuthFailed(when:Long, ip:String, user:String)
case class GeoLoc(ip:String, country:String, region:String, city:String)
object GeoLoc {
def apply(ip:String): GeoLoc = {
val rq = Source.fromURL(s"http://freegeoip.net/json/$ip")
val res = rq.getLines.mkString("")
def ex(re:Regex):Map[String,String] = {
re.findAllMatchIn(res).map { m =>
m.group(1) -> m.group(2)
}.toMap
}
val ms = ex(jstrRE)++ex(jnumRE)
GeoLoc(
ms.getOrElse("ip",""),
ms.getOrElse("country_name",""),
ms.getOrElse("region_name",""),
ms.getOrElse("city","")
)
}
}
val failures = for {
logfile <- logfiles
failRE(datestr, user, ip) <- Source.fromInputStream(inputStream(logfile)).getLines.toStream if ip != "127.0.0.1"
} yield AuthFailed(logdatefmt.parse(datestr).getTime, ip,user)
val ips = failures.map(_.ip)
val geos = ips.distinct.map(GeoLoc(_))
val users = failures.map(_.user).distinct
val topcount=10
def groupNcount[T](things:List[T])(by: T=>String):List[Tuple2[String,Int]]={
things
.groupBy(by)
.map{case (c, l) => c-> l.size}
.toList
.sortBy{case (_, n) => -n}
}
println("-----------------------------")
println("-- SSH failed distinct attempts by country")
groupNcount(geos)(_.country)
.foreach{case (country, count) => println(s"$country -> $count")}
println("-----------------------------")
println(s"-- SSH top $topcount of tested users")
groupNcount(failures)(_.user)
.take(topcount)
.foreach{case (user, count) => println(s"User '$user' -> $count")}
println("-----------------------------")
println("-- General Information")
val whens = failures.map(_.when)
val hours=(whens.max-whens.min)/(1000*3600)
val days=hours/24
println(s"Processed time range : $hours hours (~$days days)")
println(s"Total number of auth failures ${failures.size} (~${failures.size/hours} by hour)")
println(s"Distinct tested logins ${users.size}")
println(s"Total number of distinct client ip ${ips.distinct.size}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment