diff --git a/src/Val.cc b/src/Val.cc index 2df395eb03..3cb497ebe6 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -943,28 +943,50 @@ static std::variant BuildVal(const rapidjson::Value& j, con } case TYPE_PORT: { - if ( ! j.IsString() ) - return mismatch_err(); - - int port = 0; - if ( j.GetStringLength() > 0 && j.GetStringLength() < 10 ) { - char* slash; - errno = 0; - port = strtol(j.GetString(), &slash, 10); - if ( ! errno ) { - ++slash; - if ( util::streq(slash, "tcp") ) - return val_mgr->Port(port, TRANSPORT_TCP); - else if ( util::streq(slash, "udp") ) - return val_mgr->Port(port, TRANSPORT_UDP); - else if ( util::streq(slash, "icmp") ) - return val_mgr->Port(port, TRANSPORT_ICMP); - else if ( util::streq(slash, "unknown") ) - return val_mgr->Port(port, TRANSPORT_UNKNOWN); + if ( j.IsString() ) { + int port = 0; + if ( j.GetStringLength() > 0 && j.GetStringLength() < 10 ) { + char* slash; + errno = 0; + port = strtol(j.GetString(), &slash, 10); + if ( ! errno ) { + ++slash; + if ( util::streq(slash, "tcp") ) + return val_mgr->Port(port, TRANSPORT_TCP); + else if ( util::streq(slash, "udp") ) + return val_mgr->Port(port, TRANSPORT_UDP); + else if ( util::streq(slash, "icmp") ) + return val_mgr->Port(port, TRANSPORT_ICMP); + else if ( util::streq(slash, "unknown") ) + return val_mgr->Port(port, TRANSPORT_UNKNOWN); + } } - } - return "wrong port format, must be /[0-9]{1,5}\\/(tcp|udp|icmp|unknown)/"; + return "wrong port format, string must be /[0-9]{1,5}\\/(tcp|udp|icmp|unknown)/"; + } + else if ( j.IsObject() ) { + if ( ! j.HasMember("port") || ! j.HasMember("proto") ) + return "wrong port format, object must have 'port' and 'proto' members"; + if ( ! j["port"].IsNumber() ) + return "wrong port format, port must be a number"; + if ( ! j["proto"].IsString() ) + return "wrong port format, protocol must be a string"; + + std::string proto{j["proto"].GetString()}; + + if ( proto == "tcp" ) + return val_mgr->Port(j["port"].GetInt(), TRANSPORT_TCP); + if ( proto == "udp" ) + return val_mgr->Port(j["port"].GetInt(), TRANSPORT_UDP); + if ( proto == "icmp" ) + return val_mgr->Port(j["port"].GetInt(), TRANSPORT_ICMP); + if ( proto == "unknown" ) + return val_mgr->Port(j["port"].GetInt(), TRANSPORT_UNKNOWN); + + return "wrong port format, invalid protocol string"; + } + else + return "wrong port format, must be string or object"; } case TYPE_PATTERN: { diff --git a/testing/btest/Baseline/bifs.from_json-6/.stderr b/testing/btest/Baseline/bifs.from_json-6/.stderr index bafb1a49e9..0b278db5ae 100644 --- a/testing/btest/Baseline/bifs.from_json-6/.stderr +++ b/testing/btest/Baseline/bifs.from_json-6/.stderr @@ -1,2 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -error in <...>/from_json.zeek, line 5: wrong port format, must be <...>/(tcp|udp|icmp|unknown)/ (from_json("80", to_any_coerce port_t, from_json_default_key_mapper)) +error in <...>/from_json.zeek, line 8: wrong port format, string must be <...>/(tcp|udp|icmp|unknown)/ (from_json("80", to_any_coerce port_t, from_json_default_key_mapper)) +error in <...>/from_json.zeek, line 9: wrong port format, object must have 'port' and 'proto' members (from_json({}, to_any_coerce port_t, from_json_default_key_mapper)) diff --git a/testing/btest/Baseline/bifs.from_json-6/.stdout b/testing/btest/Baseline/bifs.from_json-6/.stdout index aee95c8a8e..a4da3aa3e4 100644 --- a/testing/btest/Baseline/bifs.from_json-6/.stdout +++ b/testing/btest/Baseline/bifs.from_json-6/.stdout @@ -1,2 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[v=80/tcp, valid=T] +[v=, valid=F] [v=, valid=F] diff --git a/testing/btest/bifs/from_json.zeek b/testing/btest/bifs/from_json.zeek index 9351c3b9ca..1348933123 100644 --- a/testing/btest/bifs/from_json.zeek +++ b/testing/btest/bifs/from_json.zeek @@ -73,10 +73,14 @@ event zeek_init() @TEST-START-NEXT type port_t: port; -# wrong port format +# additional & incorrect port formats event zeek_init() { + # Ports can also be given as objects: + print from_json("{\"port\":80,\"proto\":\"tcp\"}", port_t); + # These are violations: print from_json("\"80\"", port_t); + print from_json("{}", port_t); } @TEST-START-NEXT