summaryrefslogtreecommitdiff
path: root/src/main/scala/com/tylerstonge/honeypot/ftp/FtpHandler.scala
blob: 187017bb69771170dd527bc2354ebe51d89bf1d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
import com.tylerstonge.honeypot.messages.{MFoundPassword, MFoundUsername}

import scala.util.Random

object FtpHandler {
  def props(client: ActorRef): Props = Props(new FtpHandler(client))
}

class FtpHandler(client: ActorRef) extends Actor {

  val log: LoggingAdapter = Logging(context.system, this)
  var fileReceiver: ActorRef = ActorRef.noSender

  override def receive: Receive = {
    case Received(data) => client ! Write(ByteString.apply(parse(sanitize(data))))
    case PeerClosed =>
      log.debug("peer closed connection")
      context.stop(self)
  }

  def parse(msg: Array[String]): String = msg(0) match {
    case "user" =>
      log.debug("attempted login with username: {}", msg(1))
      context.system.eventStream.publish(MFoundUsername(msg(1)))
      "331 Please specify password.\n"
    case "pass" =>
      log.debug("attempted login with password: {}", msg(1))
      context.system.eventStream.publish(MFoundPassword(msg(1)))
      "230 Login successful.\n"
    case "pwd" => "257 \"/\" is the current directory\n"
    case "quit" => "221 Goodbye.\n"
    case "pasv" =>
      log.debug("entering passive mode")
      val r = new Random()
      val p1 = r.nextInt(200)
      val p2 = r.nextInt(200)
      fileReceiver = context.actorOf(FtpFileReceiver.props(p1 * 256 + p2, client), name = "passive-connection-" + (p1 * 256 + p2))
      Thread.sleep(256)
      "227 entering passive mode (127,0,0,1," + p1 + "," + p2 + ")\n"
    case "stor" =>
      log.debug("stor: {}", msg(1))
      fileReceiver ! SetName(msg(1))
      "150 File status okay; about to open data connection.\n"
    case _ =>
      log.debug("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
  }
}