diff --git a/include/IpAddress.h b/include/IpAddress.h index a50a0f719a..c939451455 100644 --- a/include/IpAddress.h +++ b/include/IpAddress.h @@ -70,6 +70,7 @@ class IpAddress { inline bool isMulticastAddress() { return(addr.multicastIP); }; inline bool isBroadcastAddress() { return(addr.broadcastIP); }; char* print(char *str, u_int str_len, u_int8_t bitmask = 0xFF); + char* printMask(char *str, u_int str_len, bool isLocalIP); bool isLocalHost(int16_t *network_id); bool isLocalInterfaceAddress(); void deserialize(json_object *o); diff --git a/include/Prefs.h b/include/Prefs.h index 54e7399f8d..936c58e1e1 100644 --- a/include/Prefs.h +++ b/include/Prefs.h @@ -51,6 +51,7 @@ class Prefs { enable_probing_alerts, enable_syslog_alerts, dump_flow_alerts_when_iface_alerted, enable_top_talkers, enable_captive_portal, enable_access_log, enable_flow_device_port_rrd_creation, enable_tiny_flows_export; + HostMask hostMask; LocationPolicy dump_hosts_to_db, sticky_hosts; u_int non_local_host_max_idle, local_host_cache_duration, local_host_max_idle, flow_max_idle; u_int active_local_hosts_cache_interval; @@ -240,6 +241,7 @@ class Prefs { inline bool hasCmdlTraceLevel() { return has_cmdl_trace_lvl; } inline bool hasCmdlDisableAlerts() { return has_cmdl_disable_alerts; } inline bool isCaptivePortalEnabled() { return(enable_captive_portal); } + inline HostMask getHostMask() { return(hostMask); } }; #endif /* _PREFS_H_ */ diff --git a/include/Utils.h b/include/Utils.h index 9fad595be6..501f1bed76 100755 --- a/include/Utils.h +++ b/include/Utils.h @@ -102,6 +102,7 @@ class Utils { static void replacestr(char *line, const char *search, const char *replace); static u_int32_t getHostManagementIPv4Address(); static bool isInterfaceUp(char *ifname); + static bool maskHost(bool isLocalIP); }; #endif /* _UTILS_H_ */ diff --git a/include/ntop_defines.h b/include/ntop_defines.h index 1d67060fcd..eecdc47ccb 100644 --- a/include/ntop_defines.h +++ b/include/ntop_defines.h @@ -419,6 +419,7 @@ #define CONST_RUNTIME_PREFS_ALERT_NAGIOS "ntopng.prefs.alerts_nagios" /* 0 / 1 */ #define CONST_RUNTIME_PREFS_DAILY_REPORTS "ntopng.prefs.daily_reports" /* 0 / 1 */ #endif +#define CONST_RUNTIME_PREFS_HOSTMASK "ntopng.prefs.host_mask" #define CONST_MAX_ALERT_MSG_QUEUE_LEN 8192 #define CONST_MAX_ES_MSG_QUEUE_LEN 8192 diff --git a/include/ntop_typedefs.h b/include/ntop_typedefs.h index 3a90c14b68..21035b5c59 100644 --- a/include/ntop_typedefs.h +++ b/include/ntop_typedefs.h @@ -22,6 +22,12 @@ #ifndef _NTOP_TYPEDEFS_H_ #define _NTOP_TYPEDEFS_H_ +typedef enum { + no_host_mask = 0, + mask_local_hosts = 1, + mask_remote_hosts = 2 +} HostMask; + typedef enum { threshold_hourly = 0, threshold_daily diff --git a/scripts/locales/en.lua b/scripts/locales/en.lua index daf41f3dce..a3baff9413 100644 --- a/scripts/locales/en.lua +++ b/scripts/locales/en.lua @@ -582,6 +582,12 @@ local en = { ldap_local = "LDAP/Local", posix = "Posix", samaccount = "sAMAccount", + host_mask = "Mask Host IP Addresses", + toggle_host_mask_title = "Mask Host IP Addresses", + toggle_host_mask_description = "For privacy reasons it might be necessary to mask hosts IP addresses. For instance if you are an ISP you are not supposed to know what local addresses are accessing rmote hosts.", + no_host_mask = "Don't Mask Hosts", + local_host_mask = "Mask Local Hosts", + remote_host_mask = "Mask Remote Hosts", }, noTraffic = "No traffic has been reported for the specified date/time selection", diff --git a/scripts/lua/admin/prefs.lua b/scripts/lua/admin/prefs.lua index 3054b54d12..3ef89cca80 100644 --- a/scripts/lua/admin/prefs.lua +++ b/scripts/lua/admin/prefs.lua @@ -374,11 +374,27 @@ function printMisc() print(''..i18n("prefs.report_units")..'') - local labels = {i18n("bytes"), i18n("packets")} - local values = {"bps", "pps"} + local t_labels = {i18n("bytes"), i18n("packets")} + local t_values = {"bps", "pps"} multipleTableButtonPrefs(subpage_active.entries["toggle_thpt_content"].title, subpage_active.entries["toggle_thpt_content"].description, - labels, values, "bps", "primary", "toggle_thpt_content", "ntopng.prefs.thpt_content") + t_labels, t_values, "bps", "primary", "toggle_thpt_content", "ntopng.prefs.thpt_content") + + -- ###################### + + if(haveAdminPrivileges()) then + print(''..i18n("prefs.host_mask")..'') + + local h_labels = {i18n("prefs.no_host_mask"), i18n("prefs.local_host_mask"), i18n("prefs.remote_host_mask")} + local h_values = {"0", "1", "2"} + + multipleTableButtonPrefs(subpage_active.entries["toggle_host_mask"].title, + subpage_active.entries["toggle_host_mask"].description, + h_labels, h_values, "0", "primary", "toggle_host_mask", "ntopng.prefs.host_mask") + end + + -- ##################### + print('') print('') print [[ diff --git a/scripts/lua/host_details.lua b/scripts/lua/host_details.lua index f16f93c693..c385ef7d63 100644 --- a/scripts/lua/host_details.lua +++ b/scripts/lua/host_details.lua @@ -75,6 +75,7 @@ end only_historical = false local host_pool_id + if (host ~= nil) then if (isAdministrator() and (_POST["pool"] ~= nil)) then host_pool_id = _POST["pool"] diff --git a/scripts/lua/modules/http_lint.lua b/scripts/lua/modules/http_lint.lua index 53fb930ab0..5f801bcea2 100644 --- a/scripts/lua/modules/http_lint.lua +++ b/scripts/lua/modules/http_lint.lua @@ -784,6 +784,7 @@ local known_parameters = { ["multiple_ldap_account_type"] = validateChoiceInline({"posix","samaccount"}), ["toggle_logging_level"] = validateChoiceInline({"trace", "debug", "info", "normal", "warning", "error"}), ["toggle_thpt_content"] = validateChoiceInline({"bps", "pps"}), + ["toggle_host_mask"] = validateChoiceInline({"0", "1", "2"}), -- -- PAGE SPECIFIC diff --git a/scripts/lua/modules/lua_utils.lua b/scripts/lua/modules/lua_utils.lua index e94668d1c0..9954f04881 100644 --- a/scripts/lua/modules/lua_utils.lua +++ b/scripts/lua/modules/lua_utils.lua @@ -1417,7 +1417,7 @@ end -- hostinfo2url(flow[key],"srv"), return an url based on the server host information in the flow table -- -function hostinfo2url(host_info,host_type,novlan) +function hostinfo2url(host_info, host_type, novlan) local rsp = '' -- local version = 0 local version = 1 diff --git a/scripts/lua/modules/prefs_utils.lua b/scripts/lua/modules/prefs_utils.lua index 20fe369b86..204c75cef6 100644 --- a/scripts/lua/modules/prefs_utils.lua +++ b/scripts/lua/modules/prefs_utils.lua @@ -246,6 +246,9 @@ menu_subpages = { }, toggle_thpt_content = { title = i18n("prefs.toggle_thpt_content_title"), description = i18n("prefs.toggle_thpt_content_description"), + }, toggle_host_mask = { + title = i18n("prefs.toggle_host_mask_title"), + description = i18n("prefs.toggle_host_mask_description"), } }}, {id="bridging", label=i18n("prefs.traffic_bridging"), advanced=false, pro_only=true, enterprise_only=true, disabled=(not hasBridgeInterfaces()), entries={ toggle_shaping_directions = { diff --git a/src/Flow.cpp b/src/Flow.cpp index a315cbbdf3..ec1ecc291d 100644 --- a/src/Flow.cpp +++ b/src/Flow.cpp @@ -1301,7 +1301,8 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, char buf[64]; Host *src = get_cli_host(), *dst = get_srv_host(); bool src_match, dst_match; - + bool mask_cli_host = true, mask_dst_host = true, mask_flow; + if((src == NULL) || (dst == NULL)) return; if(ptree) { @@ -1313,8 +1314,12 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, lua_newtable(vm); if(src) { - lua_push_str_table_entry(vm, "cli.ip", src->get_ip()->print(buf, sizeof(buf))); - lua_push_int_table_entry(vm, "cli.key", src->key()); + mask_cli_host = Utils::maskHost(src->isLocalHost()); + + lua_push_str_table_entry(vm, "cli.ip", + src->get_ip()->printMask(buf, sizeof(buf), + src->isLocalHost())); + lua_push_int_table_entry(vm, "cli.key", mask_cli_host ? 0 : src->key()); } else { lua_push_nil_table_entry(vm, "cli.ip"); lua_push_nil_table_entry(vm, "cli.key"); @@ -1322,20 +1327,25 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, lua_push_int_table_entry(vm, "cli.port", get_cli_port()); if(dst) { - lua_push_str_table_entry(vm, "srv.ip", dst->get_ip()->print(buf, sizeof(buf))); - lua_push_int_table_entry(vm, "srv.key", dst->key()); + mask_dst_host = Utils::maskHost(dst->isLocalHost()); + + lua_push_str_table_entry(vm, "srv.ip", + dst->get_ip()->printMask(buf, sizeof(buf), + dst->isLocalHost())); + lua_push_int_table_entry(vm, "srv.key", mask_dst_host ? 0 : dst->key()); } else { lua_push_nil_table_entry(vm, "srv.ip"); lua_push_nil_table_entry(vm, "srv.key"); } lua_push_int_table_entry(vm, "srv.port", get_srv_port()); + mask_flow = mask_cli_host || mask_dst_host; + lua_push_int_table_entry(vm, "bytes", cli2srv_bytes+srv2cli_bytes); lua_push_int_table_entry(vm, "goodput_bytes", cli2srv_goodput_bytes+srv2cli_goodput_bytes); if(details_level >= details_high) { - - if(src) { + if(src && !mask_cli_host) { lua_push_str_table_entry(vm, "cli.host", src->get_name(buf, sizeof(buf), false)); lua_push_int_table_entry(vm, "cli.source_id", src->getSourceId()); lua_push_str_table_entry(vm, "cli.mac", Utils::formatMac(src->get_mac(), buf, sizeof(buf))); @@ -1347,7 +1357,7 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, lua_push_nil_table_entry(vm, "cli.host"); } - if(dst) { + if(dst && !mask_dst_host) { lua_push_str_table_entry(vm, "srv.host", dst->get_name(buf, sizeof(buf), false)); lua_push_int_table_entry(vm, "srv.source_id", src->getSourceId()); lua_push_str_table_entry(vm, "srv.mac", Utils::formatMac(dst->get_mac(), buf, sizeof(buf))); @@ -1381,7 +1391,7 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, } #ifdef NTOPNG_PRO - if(trafficProfile && ntop->getPro()->has_valid_license()) + if((!mask_flow) && trafficProfile && ntop->getPro()->has_valid_license()) lua_push_str_table_entry(vm, "profile", trafficProfile->getName()); #endif @@ -1452,9 +1462,11 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, lua_push_bool_table_entry(vm, "tcp_established", isEstablished()); } - if(host_server_name) lua_push_str_table_entry(vm, "host_server_name", host_server_name); - if(bt_hash) lua_push_str_table_entry(vm, "bittorrent_hash", bt_hash); - + if(!mask_flow) { + if(host_server_name) lua_push_str_table_entry(vm, "host_server_name", host_server_name); + if(bt_hash) lua_push_str_table_entry(vm, "bittorrent_hash", bt_hash); + } + if(isHTTP() && protos.http.last_method && protos.http.last_url) { lua_push_str_table_entry(vm, "protos.http.last_method", protos.http.last_method); lua_push_int_table_entry(vm, "protos.http.last_return_code", protos.http.last_return_code); @@ -1470,26 +1482,28 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, } #endif - if(isHTTP() && protos.http.last_method && protos.http.last_url) - lua_push_str_table_entry(vm, "protos.http.last_url", protos.http.last_url); - - if(host_server_name) - lua_push_str_table_entry(vm, "protos.http.server_name", host_server_name); - - if(isDNS() && protos.dns.last_query) - lua_push_str_table_entry(vm, "protos.dns.last_query", protos.dns.last_query); - - if(isSSH()) { - if(protos.ssh.client_signature) lua_push_str_table_entry(vm, "protos.ssh.client_signature", protos.ssh.client_signature); - if(protos.ssh.server_signature) lua_push_str_table_entry(vm, "protos.ssh.server_signature", protos.ssh.server_signature); - } - - if(isSSL()) { - if(protos.ssl.certificate) - lua_push_str_table_entry(vm, "protos.ssl.certificate", protos.ssl.certificate); - - if(protos.ssl.server_certificate) - lua_push_str_table_entry(vm, "protos.ssl.server_certificate", protos.ssl.server_certificate); + if(!mask_flow) { + if(isHTTP() && protos.http.last_method && protos.http.last_url) + lua_push_str_table_entry(vm, "protos.http.last_url", protos.http.last_url); + + if(host_server_name && (!mask_flow)) + lua_push_str_table_entry(vm, "protos.http.server_name", host_server_name); + + if(isDNS() && protos.dns.last_query) + lua_push_str_table_entry(vm, "protos.dns.last_query", protos.dns.last_query); + + if(isSSH()) { + if(protos.ssh.client_signature) lua_push_str_table_entry(vm, "protos.ssh.client_signature", protos.ssh.client_signature); + if(protos.ssh.server_signature) lua_push_str_table_entry(vm, "protos.ssh.server_signature", protos.ssh.server_signature); + } + + if(isSSL()) { + if(protos.ssl.certificate) + lua_push_str_table_entry(vm, "protos.ssl.certificate", protos.ssl.certificate); + + if(protos.ssl.server_certificate) + lua_push_str_table_entry(vm, "protos.ssl.server_certificate", protos.ssl.server_certificate); + } } lua_push_str_table_entry(vm, "moreinfo.json", get_json_info()); @@ -1520,7 +1534,7 @@ void Flow::lua(lua_State* vm, AddressTree * ptree, dumpPacketStats(vm, true); dumpPacketStats(vm, false); - if(details_level >= details_higher) { + if((!mask_flow) && (details_level >= details_higher)) { lua_push_int_table_entry(vm, "cli2srv.goodput_bytes.last", get_current_goodput_bytes_cli2srv()); lua_push_int_table_entry(vm, "srv2cli.goodput_bytes.last", get_current_goodput_bytes_srv2cli()); diff --git a/src/Host.cpp b/src/Host.cpp index 45f3f5beac..6f20cf1f81 100644 --- a/src/Host.cpp +++ b/src/Host.cpp @@ -422,8 +422,9 @@ void Host::lua(lua_State* vm, AddressTree *ptree, bool returnHost, bool asListElement, bool exclude_deserialized_bytes) { char buf[64], buf_id[64], ip_buf[64], *ipaddr = NULL, *local_net; - - if(ptree && (!match(ptree))) + bool mask_host = Utils::maskHost(localHost); + + if((ptree && (!match(ptree))) || mask_host) return; #if 0 @@ -438,7 +439,7 @@ void Host::lua(lua_State* vm, AddressTree *ptree, #endif lua_newtable(vm); - lua_push_str_table_entry(vm, "ip", (ipaddr = ip.print(ip_buf, sizeof(ip_buf)))); + lua_push_str_table_entry(vm, "ip", (ipaddr = ip.printMask(ip_buf, sizeof(ip_buf), localHost))); lua_push_int_table_entry(vm, "ipkey", ip.key()); lua_push_str_table_entry(vm, "mac", Utils::formatMac(mac ? mac->get_mac() : NULL, buf, sizeof(buf))); @@ -453,8 +454,7 @@ void Host::lua(lua_State* vm, AddressTree *ptree, lua_push_int_table_entry(vm, "num_alerts", triggerAlerts() ? getNumAlerts() : 0); - lua_push_str_table_entry(vm, "name", - get_name(buf, sizeof(buf), false)); + lua_push_str_table_entry(vm, "name", mask_host ? (char*)"" : get_name(buf, sizeof(buf), false)); lua_push_int32_table_entry(vm, "local_network_id", local_network_id); local_net = ntop->getLocalNetworkName(local_network_id); @@ -471,7 +471,6 @@ void Host::lua(lua_State* vm, AddressTree *ptree, lua_push_str_table_entry(vm, "asname", asname); lua_push_str_table_entry(vm, "os", os); - lua_push_str_table_entry(vm, "continent", continent ? continent : (char*)""); lua_push_str_table_entry(vm, "country", country ? country : (char*)""); lua_push_int_table_entry(vm, "active_flows.as_client", num_active_flows_as_client); diff --git a/src/IpAddress.cpp b/src/IpAddress.cpp index c09c45b06b..4bbb05b755 100644 --- a/src/IpAddress.cpp +++ b/src/IpAddress.cpp @@ -162,6 +162,16 @@ char* IpAddress::print(char *str, u_int str_len, u_int8_t bitmask) { /* ******************************************* */ +char* IpAddress::printMask(char *str, u_int str_len, bool isLocalIP) { + if(Utils::maskHost(isLocalIP)) { + snprintf(str, str_len, (addr.ipVersion == 4) ? "0.0.0.0" : "::"); + return(str); + } else + return(intoa(str, str_len, 0xFF /* bitmask */)); +} + +/* ******************************************* */ + bool IpAddress::isLocalHost(int16_t *network_id) { if(addr.ipVersion == 4) { u_int32_t v = /* htonl */(addr.ipType.ipv4); @@ -250,14 +260,14 @@ bool IpAddress::match(AddressTree *tree) { else { patricia_tree_t *ptree = tree->getTree((addr.ipVersion == 4) ? true : false); patricia_node_t *node; - + if(ptree == NULL) return(true); - + if(addr.ipVersion == 4) node = Utils::ptree_match(ptree, AF_INET, (void*)&addr.ipType.ipv4, 32); else node = Utils::ptree_match(ptree, AF_INET6, (void*)&addr.ipType.ipv6, 128); - + return((node == NULL) ? false : true); } } @@ -296,7 +306,7 @@ void IpAddress::dump() { ntop->getTrace()->traceEvent(TRACE_NORMAL, "-------------------- [ System ]"); system = isLocalInterfaceAddress() ? "Yes" : "No"; ntop->getTrace()->traceEvent(TRACE_NORMAL, "--------------------"); - + ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s [Local: %s][SystemHost: %s]", print(buf, sizeof(buf)), local, system); } diff --git a/src/Prefs.cpp b/src/Prefs.cpp index 6db40aba47..4454143b3d 100755 --- a/src/Prefs.cpp +++ b/src/Prefs.cpp @@ -35,6 +35,7 @@ Prefs::Prefs(Ntop *_ntop) { max_num_hosts = MAX_NUM_INTERFACE_HOSTS, max_num_flows = MAX_NUM_INTERFACE_HOSTS; data_dir = strdup(CONST_DEFAULT_DATA_DIR); enable_access_log = false; + hostMask = no_host_mask; enable_flow_device_port_rrd_creation = false; install_dir = NULL, captureDirection = PCAP_D_INOUT; docs_dir = strdup(CONST_DEFAULT_DOCS_DIR); @@ -449,7 +450,8 @@ void Prefs::reloadPrefsFromRedis() { HOUSEKEEPING_FREQUENCY); notifications_enabled = getDefaultPrefsValue(ALERTS_MANAGER_NOTIFICATION_ENABLED, 0 /* Disabled by default */); dump_flow_alerts_when_iface_alerted = getDefaultPrefsValue(ALERTS_DUMP_DURING_IFACE_ALERTED, 0 /* Disabled by default */); - + hostMask = (HostMask)getDefaultPrefsValue(CONST_RUNTIME_PREFS_HOSTMASK, 0 /* Mask disabled by default */); + // sets to the default value in redis if no key is found getDefaultPrefsValue(CONST_RUNTIME_IS_AUTOLOGOUT_ENABLED, CONST_DEFAULT_IS_AUTOLOGOUT_ENABLED); diff --git a/src/Utils.cpp b/src/Utils.cpp index 8e2562e38f..b0fd3363bf 100755 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1339,7 +1339,7 @@ bool Utils::discardOldFilesExceeding(const char *path, const unsigned long max_s /* **************************************** */ char* Utils::formatMac(u_int8_t *mac, char *buf, u_int buf_len) { - if(mac == NULL) + if((mac == NULL) || (ntop->getPrefs()->getHostMask() != no_host_mask)) snprintf(buf, buf_len, "00:00:00:00:00:00"); else snprintf(buf, buf_len, "%02X:%02X:%02X:%02X:%02X:%02X", @@ -2053,3 +2053,24 @@ bool Utils::isInterfaceUp(char *ifname) { return(!!(ifr.ifr_flags & IFF_UP) ? true : false); } + +/* ****************************************************** */ + +bool Utils::maskHost(bool isLocalIP) { + bool mask_host = false; + + switch(ntop->getPrefs()->getHostMask()) { + case mask_local_hosts: + if(isLocalIP) mask_host = true; + break; + + case mask_remote_hosts: + if(!isLocalIP) mask_host = true; + break; + + default: + break; + } + + return(mask_host); +}