package com.tylerstonge.honeypot.ftp import java.net.InetSocketAddress import akka.actor.Actor import akka.event.{Logging, LoggingAdapter} import akka.io.Tcp.{PeerClosed, Received, Write} import akka.util.ByteString class FtpHandler extends Actor { val log: LoggingAdapter = Logging(context.system, this) override def receive: Receive = { case Received(data) => sender() ! 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" => context.actorOf(FtpFileReceiver.props(1287)) "227 entering passive mode (127,0,0,1,5,7)\n" case "port" => context.actorOf(FtpFileRetriever.props(new InetSocketAddress(getHostname(msg(1)), getPort(msg(1))))) "200 OK\n" case "stor" => "200 OK \n" case _ => log.info("unsupported command received: {}", msg.mkString(" ")) "451 Requested action aborted. Local error in processing.\n" } 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 } def sanitize(data: ByteString): Array[String] = { data.utf8String.trim.toLowerCase().split(" ") } }