type ftp_port: record; %%{ #include "zeek/Reporter.h" static zeek::RecordValPtr parse_port(const std::string& line) { auto r = zeek::make_intrusive(zeek::BifType::Record::ftp_port); bool good = false; uint32_t port = 0; uint32_t addr = 0; int32_t bytes[6]; if ( line.size() >= 11 && sscanf(line.c_str(), "%" SCNd32 ",%" SCNd32 ",%" SCNd32 ",%" SCNd32 ",%" SCNd32 ",%" SCNd32, &bytes[0], &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5]) == 6 ) { good = true; for ( int b : bytes ) if ( b < 0 || b > 255 ) { good = false; break; } if ( good ) { addr = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; port = (bytes[4] << 8) | bytes[5]; } } r->Assign(0, zeek::make_intrusive(htonl(addr))); r->Assign(1, zeek::val_mgr->Port(port, TRANSPORT_TCP)); r->Assign(2, good); return r; } static zeek::RecordValPtr parse_eftp(const char* line) { auto r = zeek::make_intrusive(zeek::BifType::Record::ftp_port); int net_proto = 0; // currently not used zeek::IPAddr addr; // unspecified IPv6 address (all 128 bits zero) int port = 0; bool good = false; if ( line ) { while ( isspace(*line) ) // skip whitespace ++line; char delimiter = *line; char* next_delim; if ( *line ) { good = true; ++line; // skip delimiter net_proto = strtol(line, &next_delim, 10); if ( *next_delim != delimiter ) good = false; line = next_delim; if ( *line ) ++line; if ( *line && *line != delimiter ) { const char* nptr = strchr(line, delimiter); if ( nptr == NULL ) nptr = line + strlen(line); std::string s(line, nptr-line); // extract IP address struct in6_addr result; good = zeek::IPAddr::ConvertString(s.c_str(), &result); if ( good ) addr = zeek::IPAddr(result); } line = strchr(line, delimiter); if ( line != NULL ) { ++line; // now the port port = strtol(line, &next_delim, 10); if ( *next_delim != delimiter ) good = false; if ( port < 0 || port > 65535 ) { port = 0; good = false; } } } } r->Assign(0, zeek::make_intrusive(addr)); r->Assign(1, zeek::val_mgr->Port(port, TRANSPORT_TCP)); r->Assign(2, good); return r; } %%} ## Converts a string representation of the FTP PORT command to an ## :zeek:type:`ftp_port`. ## ## s: The string of the FTP PORT command, e.g., ``"10,0,0,1,4,31"``. ## ## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]``. ## ## .. zeek:see:: parse_eftp_port parse_ftp_pasv parse_ftp_epsv fmt_ftp_port function parse_ftp_port%(s: string%): ftp_port %{ return parse_port(s->ToStdString()); %} ## Converts a string representation of the FTP EPRT command (see :rfc:`2428`) ## to an :zeek:type:`ftp_port`. The format is ## ``"EPRT"``, ## where ```` is a delimiter in the ASCII range 33-126 (usually ``|``). ## ## s: The string of the FTP EPRT command, e.g., ``"|1|10.0.0.1|1055|"``. ## ## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]``. ## ## .. zeek:see:: parse_ftp_port parse_ftp_pasv parse_ftp_epsv fmt_ftp_port function parse_eftp_port%(s: string%): ftp_port %{ return parse_eftp(s->CheckString()); %} ## Converts the result of the FTP PASV command to an :zeek:type:`ftp_port`. ## ## str: The string containing the result of the FTP PASV command. ## ## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]``. ## ## .. zeek:see:: parse_ftp_port parse_eftp_port parse_ftp_epsv fmt_ftp_port function parse_ftp_pasv%(str: string%): ftp_port %{ const char* s = str->CheckString(); if ( str->Len() == 0 ) return parse_port(""); const char* line = strchr(s, '('); if ( line ) ++line; // move past '(' else if ( line = strstr(s, "PORT"); line != nullptr ) line += 5; // Skip over else if ( line = strchr(s, ','); line != nullptr ) { // Look for comma-separated list. do { // Back up over preceding digits. We'll end on the // first digit or the beginning of s. --line; } while ( line >= s && isdigit(*line) ); // Scoot forward one to point at the first digit or at the // beginning of s. ++line; } // Make sure we didn't step past the end of the string. if ( ! line || ( line - s ) > str->Len() ) return parse_port(""); else return parse_port(std::string{line}); %} ## Converts the result of the FTP EPSV command (see :rfc:`2428`) to an ## :zeek:type:`ftp_port`. The format is ``" ()"``, ## where ```` is a delimiter in the ASCII range 33-126 (usually ``|``). ## ## str: The string containing the result of the FTP EPSV command. ## ## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]``. ## ## .. zeek:see:: parse_ftp_port parse_eftp_port parse_ftp_pasv fmt_ftp_port function parse_ftp_epsv%(str: string%): ftp_port %{ const char* s = str->CheckString(); const char* line = strchr(s, '('); if ( line ) ++line; // move past '(' return parse_eftp(line); %} ## Formats an IP address and TCP port as an FTP PORT command. For example, ## ``10.0.0.1`` and ``1055/tcp`` yields ``"10,0,0,1,4,31"``. ## ## a: The IP address. ## ## p: The TCP port. ## ## Returns: The FTP PORT string. ## ## .. zeek:see:: parse_ftp_port parse_eftp_port parse_ftp_pasv parse_ftp_epsv function fmt_ftp_port%(a: addr, p: port%): string %{ const uint32_t* addr; int len = a->AsAddr().GetBytes(&addr); if ( len == 1 ) { uint32_t a = ntohl(addr[0]); uint32_t pn = p->Port(); return zeek::make_intrusive(zeek::util::fmt("%d,%d,%d,%d,%d,%d", a >> 24, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff, pn >> 8, pn & 0xff)); } else { zeek::emit_builtin_error("conversion of non-IPv4 address in fmt_ftp_port", @ARG@[0]); return zeek::val_mgr->EmptyString(); } %}