package com.tylerstonge.honeypot.ftp import akka.actor.{Actor, ActorRef, Props} import akka.event.{Logging, LoggingAdapter} import akka.io.Tcp.{PeerClosed, Received, Write} import akka.util.ByteString object FtpHandler { def props(client: ActorRef): Props = Props(new FtpHandler(client)) } class FtpHandler(client: ActorRef) extends Actor { val log: LoggingAdapter = Logging(context.system, this) override def receive: Receive = { case Received(data) => client ! Write(ByteString.apply(parse(sanitize(data)))) case PeerClosed => log.info("peer closed connection") context.stop(self) } def parse(msg: Array[String]): String = msg(0) match { case "user" => log.info("attempted login with username: {}", msg(1)) "331 Please specify password.\n" case "pass" => log.info("attempted login with password: {}", msg(1)) "230 Login successful.\n" case "pwd" => "257 \"/\" is the current directory\n" case "quit" => "221 Goodbye.\n" case "pasv" => log.info("entering passive mode") context.actorOf(FtpFileReceiver.props(1287, client), name = "passive-connection") Thread.sleep(256) "227 entering passive mode (127,0,0,1,5,7)\n" case "stor" => log.info("stor: {}", msg(1)) "150 File status okay; about to open data connection.\n" case _ => log.info("unsupported command received: {}", msg.mkString(" ")) "451 Requested action aborted. Local error in processing.\n" } def sanitize(data: ByteString): Array[String] = { data.utf8String.trim.toLowerCase().split(" ") } def getHostname(msg: String): String = { val split = msg.split(",") split.slice(0, 4).mkString(".") } def getPort(msg: String): Int = { val split = msg.split(",") split(4).toInt * 256 + split(5).toInt } }