mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 22:58:20 +00:00
Deprecate global Val pointers in NetVar.h
All of these have fairly niche uses, so better maintained as lookup/static closer to the usage site.
This commit is contained in:
parent
c0986f0739
commit
d34b24e776
13 changed files with 83 additions and 49 deletions
27
src/Anon.cc
27
src/Anon.cc
|
@ -10,6 +10,8 @@
|
|||
#include "Val.h"
|
||||
#include "NetVar.h"
|
||||
#include "Reporter.h"
|
||||
#include "Scope.h"
|
||||
#include "ID.h"
|
||||
|
||||
|
||||
AnonymizeIPAddr* ip_anonymizer[NUM_ADDR_ANONYMIZATION_METHODS] = {nullptr};
|
||||
|
@ -354,6 +356,10 @@ AnonymizeIPAddr_A50::Node* AnonymizeIPAddr_A50::find_node(ipaddr32_t a)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static IntrusivePtr<TableVal> anon_preserve_orig_addr;
|
||||
static IntrusivePtr<TableVal> anon_preserve_resp_addr;
|
||||
static IntrusivePtr<TableVal> anon_preserve_other_addr;
|
||||
|
||||
void init_ip_addr_anonymizers()
|
||||
{
|
||||
ip_anonymizer[KEEP_ORIG_ADDR] = nullptr;
|
||||
|
@ -361,6 +367,21 @@ void init_ip_addr_anonymizers()
|
|||
ip_anonymizer[RANDOM_MD5] = new AnonymizeIPAddr_RandomMD5();
|
||||
ip_anonymizer[PREFIX_PRESERVING_A50] = new AnonymizeIPAddr_A50();
|
||||
ip_anonymizer[PREFIX_PRESERVING_MD5] = new AnonymizeIPAddr_PrefixMD5();
|
||||
|
||||
auto id = global_scope()->Lookup("preserve_orig_addr");
|
||||
|
||||
if ( id )
|
||||
anon_preserve_orig_addr = cast_intrusive<TableVal>(id->GetVal());
|
||||
|
||||
id = global_scope()->Lookup("preserve_resp_addr");
|
||||
|
||||
if ( id )
|
||||
anon_preserve_resp_addr = cast_intrusive<TableVal>(id->GetVal());
|
||||
|
||||
id = global_scope()->Lookup("preserve_other_addr");
|
||||
|
||||
if ( id )
|
||||
anon_preserve_other_addr = cast_intrusive<TableVal>(id->GetVal());
|
||||
}
|
||||
|
||||
ipaddr32_t anonymize_ip(ipaddr32_t ip, enum ip_addr_anonymization_class_t cl)
|
||||
|
@ -372,17 +393,17 @@ ipaddr32_t anonymize_ip(ipaddr32_t ip, enum ip_addr_anonymization_class_t cl)
|
|||
|
||||
switch ( cl ) {
|
||||
case ORIG_ADDR: // client address
|
||||
preserve_addr = preserve_orig_addr;
|
||||
preserve_addr = anon_preserve_orig_addr.get();
|
||||
method = orig_addr_anonymization;
|
||||
break;
|
||||
|
||||
case RESP_ADDR: // server address
|
||||
preserve_addr = preserve_resp_addr;
|
||||
preserve_addr = anon_preserve_resp_addr.get();
|
||||
method = resp_addr_anonymization;
|
||||
break;
|
||||
|
||||
default:
|
||||
preserve_addr = preserve_other_addr;
|
||||
preserve_addr = anon_preserve_other_addr.get();
|
||||
method = other_addr_anonymization;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -205,11 +205,6 @@ void init_general_global_var()
|
|||
table_expire_delay = opt_internal_double("table_expire_delay");
|
||||
table_incremental_step = opt_internal_int("table_incremental_step");
|
||||
|
||||
log_rotate_base_time = opt_internal_string("log_rotate_base_time");
|
||||
|
||||
peer_description =
|
||||
zeek::lookup_val("peer_description")->AsStringVal();
|
||||
|
||||
packet_filter_default = opt_internal_int("packet_filter_default");
|
||||
|
||||
sig_max_group_size = opt_internal_int("sig_max_group_size");
|
||||
|
@ -219,15 +214,8 @@ void init_general_global_var()
|
|||
|
||||
suppress_local_output = opt_internal_int("suppress_local_output");
|
||||
|
||||
trace_output_file = zeek::lookup_val("trace_output_file")->AsStringVal();
|
||||
|
||||
record_all_packets = opt_internal_int("record_all_packets");
|
||||
|
||||
cmd_line_bpf_filter =
|
||||
zeek::lookup_val("cmd_line_bpf_filter")->AsStringVal();
|
||||
|
||||
global_hash_seed = opt_internal_string("global_hash_seed");
|
||||
|
||||
bits_per_uid = opt_internal_unsigned("bits_per_uid");
|
||||
}
|
||||
|
||||
|
@ -273,26 +261,11 @@ void init_net_var()
|
|||
tcp_storm_interarrival_thresh =
|
||||
opt_internal_double("tcp_storm_interarrival_thresh");
|
||||
|
||||
tcp_reassembler_ports_orig =
|
||||
zeek::lookup_val("tcp_reassembler_ports_orig")->AsTableVal();
|
||||
tcp_reassembler_ports_resp =
|
||||
zeek::lookup_val("tcp_reassembler_ports_resp")->AsTableVal();
|
||||
|
||||
tcp_content_delivery_ports_orig =
|
||||
zeek::lookup_val("tcp_content_delivery_ports_orig")->AsTableVal();
|
||||
tcp_content_delivery_ports_resp =
|
||||
zeek::lookup_val("tcp_content_delivery_ports_resp")->AsTableVal();
|
||||
tcp_content_deliver_all_orig =
|
||||
bool(zeek::lookup_val("tcp_content_deliver_all_orig")->AsBool());
|
||||
tcp_content_deliver_all_resp =
|
||||
bool(zeek::lookup_val("tcp_content_deliver_all_resp")->AsBool());
|
||||
|
||||
udp_content_delivery_ports_orig =
|
||||
zeek::lookup_val("udp_content_delivery_ports_orig")->AsTableVal();
|
||||
udp_content_delivery_ports_resp =
|
||||
zeek::lookup_val("udp_content_delivery_ports_resp")->AsTableVal();
|
||||
udp_content_ports =
|
||||
zeek::lookup_val("udp_content_ports")->AsTableVal();
|
||||
udp_content_deliver_all_orig =
|
||||
bool(zeek::lookup_val("udp_content_deliver_all_orig")->AsBool());
|
||||
udp_content_deliver_all_resp =
|
||||
|
@ -313,28 +286,20 @@ void init_net_var()
|
|||
http_entity_data_delivery_size = opt_internal_int("http_entity_data_delivery_size");
|
||||
truncate_http_URI = opt_internal_int("truncate_http_URI");
|
||||
|
||||
dns_skip_auth = zeek::lookup_val("dns_skip_auth")->AsTableVal();
|
||||
dns_skip_addl = zeek::lookup_val("dns_skip_addl")->AsTableVal();
|
||||
dns_skip_all_auth = opt_internal_int("dns_skip_all_auth");
|
||||
dns_skip_all_addl = opt_internal_int("dns_skip_all_addl");
|
||||
dns_max_queries = opt_internal_int("dns_max_queries");
|
||||
|
||||
stp_delta = opt_internal_double("stp_delta");
|
||||
stp_idle_min = opt_internal_double("stp_idle_min");
|
||||
stp_skip_src = zeek::lookup_val("stp_skip_src")->AsTableVal();
|
||||
|
||||
orig_addr_anonymization = opt_internal_int("orig_addr_anonymization");
|
||||
resp_addr_anonymization = opt_internal_int("resp_addr_anonymization");
|
||||
other_addr_anonymization = opt_internal_int("other_addr_anonymization");
|
||||
|
||||
preserve_orig_addr = opt_internal_table("preserve_orig_addr");
|
||||
preserve_resp_addr = opt_internal_table("preserve_resp_addr");
|
||||
preserve_other_addr = opt_internal_table("preserve_other_addr");
|
||||
|
||||
connection_status_update_interval =
|
||||
opt_internal_double("connection_status_update_interval");
|
||||
|
||||
profiling_file = zeek::lookup_val("profiling_file").get();
|
||||
expensive_profiling_multiple =
|
||||
opt_internal_int("expensive_profiling_multiple");
|
||||
profiling_interval = opt_internal_double("profiling_interval");
|
||||
|
@ -342,7 +307,6 @@ void init_net_var()
|
|||
|
||||
pkt_profile_mode = opt_internal_int("pkt_profile_mode");
|
||||
pkt_profile_freq = opt_internal_double("pkt_profile_freq");
|
||||
pkt_profile_file = zeek::lookup_val("pkt_profile_file").get();
|
||||
|
||||
load_sample_freq = opt_internal_int("load_sample_freq");
|
||||
|
||||
|
@ -355,8 +319,6 @@ void init_net_var()
|
|||
dpd_late_match_stop = opt_internal_int("dpd_late_match_stop");
|
||||
dpd_ignore_ports = opt_internal_int("dpd_ignore_ports");
|
||||
|
||||
likely_server_ports = zeek::lookup_val("likely_server_ports")->AsTableVal();
|
||||
|
||||
timer_mgr_inactivity_timeout =
|
||||
opt_internal_double("timer_mgr_inactivity_timeout");
|
||||
}
|
||||
|
|
21
src/NetVar.h
21
src/NetVar.h
|
@ -88,16 +88,23 @@ extern double icmp_inactivity_timeout;
|
|||
extern int tcp_storm_thresh;
|
||||
extern double tcp_storm_interarrival_thresh;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* tcp_reassembler_ports_orig;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* tcp_reassembler_ports_resp;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* tcp_content_delivery_ports_orig;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* tcp_content_delivery_ports_resp;
|
||||
extern bool tcp_content_deliver_all_orig;
|
||||
extern bool tcp_content_deliver_all_resp;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* udp_content_delivery_ports_orig;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* udp_content_delivery_ports_resp;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* udp_content_ports;
|
||||
extern bool udp_content_deliver_all_orig;
|
||||
extern bool udp_content_deliver_all_resp;
|
||||
|
@ -153,7 +160,9 @@ extern RecordType* dns_dnskey_rr;
|
|||
extern RecordType* dns_nsec3_rr;
|
||||
[[deprecated("Remove in v4.1. Use zeek::vars::dns_ds_rr.")]]
|
||||
extern RecordType* dns_ds_rr;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* dns_skip_auth;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* dns_skip_addl;
|
||||
extern int dns_skip_all_auth;
|
||||
extern int dns_skip_all_addl;
|
||||
|
@ -161,6 +170,7 @@ extern int dns_max_queries;
|
|||
|
||||
extern double stp_delta;
|
||||
extern double stp_idle_min;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* stp_skip_src;
|
||||
|
||||
extern double table_expire_interval;
|
||||
|
@ -169,18 +179,24 @@ extern int table_incremental_step;
|
|||
|
||||
extern int orig_addr_anonymization, resp_addr_anonymization;
|
||||
extern int other_addr_anonymization;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* preserve_orig_addr;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* preserve_resp_addr;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* preserve_other_addr;
|
||||
|
||||
extern double connection_status_update_interval;
|
||||
|
||||
[[deprecated("Remove in v4.1. Use zeek::vars::rotate_info.")]]
|
||||
extern RecordType* rotate_info;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern StringVal* log_rotate_base_time;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern StringVal* peer_description;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern Val* profiling_file;
|
||||
extern double profiling_interval;
|
||||
extern int expensive_profiling_multiple;
|
||||
|
@ -188,6 +204,7 @@ extern int expensive_profiling_multiple;
|
|||
extern int segment_profiling;
|
||||
extern int pkt_profile_mode;
|
||||
extern double pkt_profile_freq;
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern Val* pkt_profile_file;
|
||||
|
||||
extern int load_sample_freq;
|
||||
|
@ -207,6 +224,7 @@ extern int dpd_match_only_beginning;
|
|||
extern int dpd_late_match_stop;
|
||||
extern int dpd_ignore_ports;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern TableVal* likely_server_ports;
|
||||
|
||||
extern int check_for_unused_event_handlers;
|
||||
|
@ -215,6 +233,7 @@ extern int suppress_local_output;
|
|||
|
||||
extern double timer_mgr_inactivity_timeout;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern StringVal* trace_output_file;
|
||||
|
||||
extern int record_all_packets;
|
||||
|
@ -232,8 +251,10 @@ extern RecordType* call_argument;
|
|||
[[deprecated("Remove in v4.1. Use zeek::vars::call_argument_vector.")]]
|
||||
extern VectorType* call_argument_vector;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern StringVal* cmd_line_bpf_filter;
|
||||
|
||||
[[deprecated("Remove in v4.1.")]]
|
||||
extern StringVal* global_hash_seed;
|
||||
|
||||
extern bro_uint_t bits_per_uid;
|
||||
|
|
|
@ -81,6 +81,7 @@ NetSessions::NetSessions()
|
|||
|
||||
dump_this_packet = false;
|
||||
num_packets_processed = 0;
|
||||
static auto pkt_profile_file = zeek::lookup_val("pkt_profile_file");
|
||||
|
||||
if ( pkt_profile_mode && pkt_profile_freq > 0 && pkt_profile_file )
|
||||
pkt_profiler = new PacketProfiler(pkt_profile_mode,
|
||||
|
@ -1218,6 +1219,7 @@ bool NetSessions::IsLikelyServerPort(uint32_t port, TransportProto proto) const
|
|||
|
||||
if ( ! have_cache )
|
||||
{
|
||||
auto likely_server_ports = zeek::lookup_val<TableVal>("likely_server_ports");
|
||||
auto lv = likely_server_ports->ToPureListVal();
|
||||
for ( int i = 0; i < lv->Length(); i++ )
|
||||
port_cache.insert(lv->Idx(i)->InternalUnsigned());
|
||||
|
|
12
src/Var.h
12
src/Var.h
|
@ -52,7 +52,9 @@ extern Val* opt_internal_val(const char* name); // returns nil if not defined
|
|||
extern double opt_internal_double(const char* name);
|
||||
extern bro_int_t opt_internal_int(const char* name);
|
||||
extern bro_uint_t opt_internal_unsigned(const char* name);
|
||||
[[deprecated("Remove in v4.1. Use lookup_ID() or zeek::lookup_val().")]]
|
||||
extern StringVal* opt_internal_string(const char* name);
|
||||
[[deprecated("Remove in v4.1. Use lookup_ID() or zeek::lookup_val().")]]
|
||||
extern TableVal* opt_internal_table(const char* name); // nil if not defined
|
||||
|
||||
[[deprecated("Remove in v4.1. Use lookup_ID(), zeek::lookup_val(), and/or TableVal::ToPureListVal().")]]
|
||||
|
@ -96,6 +98,16 @@ IntrusivePtr<T> lookup_type(const char* name)
|
|||
*/
|
||||
const IntrusivePtr<Val>& lookup_val(const char* name);
|
||||
|
||||
/**
|
||||
* Lookup an ID by its name and return its value (as cast to @c T).
|
||||
* A fatal occurs if the ID does not exist.
|
||||
* @param name The identifier name to lookup
|
||||
* @return The current value of the identifier.
|
||||
*/
|
||||
template<class T>
|
||||
IntrusivePtr<T> lookup_val(const char* name)
|
||||
{ return cast_intrusive<T>(lookup_val(name)); }
|
||||
|
||||
/**
|
||||
* Lookup an ID by its name and return its value. A fatal occurs if the ID
|
||||
* does not exist or if it is not "const".
|
||||
|
|
|
@ -438,6 +438,8 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
|
|||
|
||||
if ( tcp_contents && ! reass )
|
||||
{
|
||||
static auto tcp_content_delivery_ports_orig = zeek::lookup_val<TableVal>("tcp_content_delivery_ports_orig");
|
||||
static auto tcp_content_delivery_ports_resp = zeek::lookup_val<TableVal>("tcp_content_delivery_ports_resp");
|
||||
const auto& dport = val_mgr->Port(ntohs(conn->RespPort()), TRANSPORT_TCP);
|
||||
|
||||
if ( ! reass )
|
||||
|
@ -460,6 +462,8 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
|
|||
uint16_t resp_port = ntohs(conn->RespPort());
|
||||
if ( resp_port == 22 || resp_port == 23 || resp_port == 513 )
|
||||
{
|
||||
static auto stp_skip_src = zeek::lookup_val<TableVal>("stp_skip_src");
|
||||
|
||||
AddrVal src(conn->OrigAddr());
|
||||
if ( ! stp_skip_src->Lookup(&src) )
|
||||
tcp->AddChildAnalyzer(new stepping_stone::SteppingStone_Analyzer(conn), false);
|
||||
|
|
|
@ -91,6 +91,9 @@ void DNS_Interpreter::ParseMessage(const u_char* data, int len, int is_query)
|
|||
int skip_addl = dns_skip_all_addl;
|
||||
if ( msg.ancount > 0 )
|
||||
{ // We did an answer, so can potentially skip auth/addl.
|
||||
static auto dns_skip_auth = zeek::lookup_val<TableVal>("dns_skip_auth");
|
||||
static auto dns_skip_addl = zeek::lookup_val<TableVal>("dns_skip_addl");
|
||||
|
||||
skip_auth = skip_auth || msg.nscount == 0 ||
|
||||
dns_skip_auth->Lookup(&server);
|
||||
skip_addl = skip_addl || msg.arcount == 0 ||
|
||||
|
|
|
@ -42,9 +42,11 @@ TCP_Reassembler::TCP_Reassembler(analyzer::Analyzer* arg_dst_analyzer,
|
|||
|
||||
if ( ::tcp_contents )
|
||||
{
|
||||
static auto tcp_content_delivery_ports_orig = zeek::lookup_val<TableVal>("tcp_content_delivery_ports_orig");
|
||||
static auto tcp_content_delivery_ports_resp = zeek::lookup_val<TableVal>("tcp_content_delivery_ports_resp");
|
||||
const auto& dst_port_val = val_mgr->Port(ntohs(tcp_analyzer->Conn()->RespPort()),
|
||||
TRANSPORT_TCP);
|
||||
TableVal* ports = IsOrig() ?
|
||||
const auto& ports = IsOrig() ?
|
||||
tcp_content_delivery_ports_orig :
|
||||
tcp_content_delivery_ports_resp;
|
||||
auto result = ports->Lookup(dst_port_val.get());
|
||||
|
|
|
@ -134,6 +134,9 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
|
|||
|
||||
if ( udp_contents )
|
||||
{
|
||||
static auto udp_content_ports = zeek::lookup_val<TableVal>("udp_content_ports");
|
||||
static auto udp_content_delivery_ports_orig = zeek::lookup_val<TableVal>("udp_content_delivery_ports_orig");
|
||||
static auto udp_content_delivery_ports_resp = zeek::lookup_val<TableVal>("udp_content_delivery_ports_resp");
|
||||
bool do_udp_contents = false;
|
||||
const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP);
|
||||
const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP);
|
||||
|
|
|
@ -1193,8 +1193,8 @@ WriterFrontend* Manager::CreateWriter(EnumVal* id, EnumVal* writer, WriterBacken
|
|||
|
||||
// Still need to set the WriterInfo's rotation parameters, which we
|
||||
// computed above.
|
||||
const char* base_time = log_rotate_base_time ?
|
||||
log_rotate_base_time->AsString()->CheckString() : nullptr;
|
||||
static auto log_rotate_base_time = zeek::lookup_val<StringVal>("log_rotate_base_time");
|
||||
static auto base_time = log_rotate_base_time->AsString()->CheckString();
|
||||
|
||||
winfo->info->rotation_interval = winfo->interval;
|
||||
winfo->info->rotation_base = parse_rotate_base_time(base_time);
|
||||
|
@ -1453,8 +1453,8 @@ void Manager::InstallRotationTimer(WriterInfo* winfo)
|
|||
if ( ! winfo->open_time )
|
||||
winfo->open_time = network_time;
|
||||
|
||||
const char* base_time = log_rotate_base_time ?
|
||||
log_rotate_base_time->AsString()->CheckString() : nullptr;
|
||||
static auto log_rotate_base_time = zeek::lookup_val<StringVal>("log_rotate_base_time");
|
||||
static auto base_time = log_rotate_base_time->AsString()->CheckString();
|
||||
|
||||
double base = parse_rotate_base_time(base_time);
|
||||
double delta_t =
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <openssl/evp.h>
|
||||
|
||||
#include "NetVar.h"
|
||||
#include "Var.h"
|
||||
#include "digest.h"
|
||||
#include "highwayhash/sip_hash.h"
|
||||
|
||||
|
@ -22,10 +23,12 @@ Hasher::seed_t Hasher::MakeSeed(const void* data, size_t size)
|
|||
|
||||
assert(sizeof(tmpseed) == 16);
|
||||
|
||||
static auto global_hash_seed = zeek::lookup_val<StringVal>("global_hash_seed");
|
||||
|
||||
if ( data )
|
||||
hash_update(ctx, data, size);
|
||||
|
||||
else if ( global_hash_seed && global_hash_seed->Len() > 0 )
|
||||
else if ( global_hash_seed->Len() > 0 )
|
||||
hash_update(ctx, global_hash_seed->Bytes(), global_hash_seed->Len());
|
||||
|
||||
else
|
||||
|
|
|
@ -784,6 +784,7 @@ zeek::detail::SetupResult zeek::detail::setup(int argc, char** argv,
|
|||
|
||||
if ( profiling_interval > 0 )
|
||||
{
|
||||
const auto& profiling_file = zeek::lookup_val("profiling_file");
|
||||
profiling_logger = new ProfileLogger(profiling_file->AsFile(),
|
||||
profiling_interval);
|
||||
|
||||
|
|
|
@ -4694,8 +4694,8 @@ function rotate_file_by_name%(f: string%): rotate_info
|
|||
## .. zeek:see:: rotate_file rotate_file_by_name
|
||||
function calc_next_rotate%(i: interval%) : interval
|
||||
%{
|
||||
const char* base_time = log_rotate_base_time ?
|
||||
log_rotate_base_time->AsString()->CheckString() : 0;
|
||||
static auto log_rotate_base_time = zeek::lookup_val<StringVal>("log_rotate_base_time");
|
||||
static auto base_time = log_rotate_base_time->AsString()->CheckString();
|
||||
|
||||
double base = parse_rotate_base_time(base_time);
|
||||
return make_intrusive<Val>(calc_next_rotate(network_time, i, base), TYPE_INTERVAL);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue