return ALPROTO_FTP;
}
+static AppProto FTPServerProbingParser(
+ Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
+{
+ // another check for minimum length
+ if (len < 5) {
+ return ALPROTO_UNKNOWN;
+ }
+ // begins by 220
+ if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
+ return ALPROTO_FAILED;
+ }
+ // followed by space or hypen
+ if (input[3] != ' ' && input[3] != '-') {
+ return ALPROTO_FAILED;
+ }
+ if (f->alproto_ts == ALPROTO_FTP || (f->todstbytecnt > 4 && f->alproto_ts == ALPROTO_UNKNOWN)) {
+ // only validates FTP if client side was FTP
+ // or if client side is unknown despite having received bytes
+ if (memchr(input + 4, '\n', len - 4) != NULL) {
+ return ALPROTO_FTP;
+ }
+ }
+ return ALPROTO_UNKNOWN;
+}
+
static int FTPRegisterPatternsForProtocolDetection(void)
{
if (AppLayerProtoDetectPMRegisterPatternCI(
IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER) < 0) {
return -1;
}
-
+ // Only check FTP on known ports as the banner has nothing special beyond
+ // the response code shared with SMTP.
+ if (!AppLayerProtoDetectPPParseConfPorts(
+ "tcp", IPPROTO_TCP, "ftp", ALPROTO_FTP, 0, 5, NULL, FTPServerProbingParser)) {
+ // STREAM_TOSERVER here means use 21 as flow destination port
+ // and NULL, FTPServerProbingParser means use probing parser to client
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP, "21", ALPROTO_FTP, 0, 5, STREAM_TOSERVER, NULL,
+ FTPServerProbingParser);
+ }
return 0;
}