-- -- (C) 2014-15 - ntop.org -- require "lua_trace" function getInterfaceName(interface_id) local ifnames = interface.getIfNames() interface_id = tonumber(interface_id) for _,if_name in pairs(ifnames) do interface.select(if_name) ifstats = interface.getStats() if(ifstats.id == interface_id) then return(ifstats.name) end end return("") end -- Note that ifname can be set by Lua.cpp so don't touch it if already defined if((ifname == nil) and (_GET ~= nil)) then ifname = _GET["ifname"] if(ifname ~= nil) then if(ifname.."" == tostring(tonumber(ifname)).."") then -- ifname does not contain the interface name but rather the interface id ifname = getInterfaceName(ifname) if(ifname == "") then ifname = nil end end end if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => Session:".._SESSION["session"]) end if((ifname == nil) and (_SESSION ~= nil)) then if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => set ifname by _SESSION value") end ifname = _SESSION["ifname"] if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => ifname:"..ifname) end else if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => set ifname by _GET value") end end end --print("(((("..ifname.."))))") l4_keys = { { "TCP", "tcp" }, { "UDP", "udp" }, { "ICMP", "icmp" }, { "Other IP", "other ip" } } function __FILE__() return debug.getinfo(2,'S').source end function __LINE__() return debug.getinfo(2, 'l').currentline end function sendHTTPHeaderIfName(mime, ifname, maxage) info = ntop.getInfo() print('HTTP/1.1 200 OK\r\n') print('Cache-Control: max-age=0, no-cache, no-store\r\n') print('Server: ntopng '..info["version"]..' ['.. info["platform"]..']\r\n') print('Pragma: no-cache\r\n') print('X-Frame-Options: DENY\r\n') print('X-Content-Type-Options: nosniff\r\n') if(_SESSION ~= nil) then print('Set-Cookie: session='.._SESSION["session"]..'; max-age=' .. maxage .. '; path=/; HttpOnly\r\n') end if(ifname ~= nil) then print('Set-Cookie: ifname=' .. ifname .. '; path=/\r\n') end print('Content-Type: '.. mime ..'\r\n') print('Last-Modified: '..os.date("!%a, %m %B %Y %X %Z").."\r\n") print('\r\n') end function sendHTTPHeaderLogout(mime) sendHTTPHeaderIfName(mime, nil, 0) end function sendHTTPHeader(mime) sendHTTPHeaderIfName(mime, nil, 3600) end function printGETParameters(get) for key, value in pairs(get) do io.write(key.."="..value.."\n") end end function isEmptyString(str) -- io.write(str..'\n') if((str == nil) or (str == "")) then return true else return false end end function findString(str, tofind) local upper_lower = true if(str == nil) then return(nil) end if(tofind == nil) then return(nil) end str1 = string.gsub(str, "-", "_") tofind1 = string.gsub(tofind, "-", "_") rsp = string.find(str1, tofind1, 1) if(upper_lower) then if(rsp == nil) then -- Lowercase str1 = string.lower(str1) tofind1 = string.lower(tofind1) rsp = string.find(str1, tofind1, 1) end if(rsp == nil) then -- Uppercase str1 = string.upper(str1) tofind1 = string.upper(tofind1) rsp = string.find(str1, tofind1, 1) end end --print(str1 .. "/" .. tofind1.."\n") --print(rsp) --print("\n") return(rsp) end function findStringArray(str, tofind) if(str == nil) then return(nil) end if(tofind == nil) then return(nil) end local rsp = false for k,v in pairs(tofind) do str1 = string.gsub(str, "-", "_") tofind1 = string.gsub(v, "-", "_") if(str1 == tofind1) then rsp = true end end return(rsp) end function string.contains(String,Start) return(string.find(String,Start,1) ~= nil) end function string.starts(String,Start) return string.sub(String,1,string.len(Start))==Start end function string.ends(String,End) return End=='' or string.sub(String,-string.len(End))==End end function printASN(asn, asname) if(asn > 0) then return(""..asname.." ") else return(asname) end end function shortenString(name) max_len = 24 if(string.len(name) < max_len) then return(name) else return(string.sub(name, 1, max_len).."...") end end function shortHostName(name) local chunks = {name:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")} if(#chunks == 4) then return(name) else max_len = 24 chunks = {name:match("%w+:%w+:%w+:%w+:%w+:%w+")} --io.write(#chunks.."\n") if(#chunks == 1) then return(name) end if(string.len(name) < max_len) then return(name) else tot = 0 n = 0 ret = "" for token in string.gmatch(name, "([%w-]+).") do if(tot < max_len) then if(n > 0) then ret = ret .. "." end ret = ret .. token tot = tot+string.len(token) n = n + 1 end end return(ret .. "...") end end return(name) end function _handleArray(name, sev) local id for id, _ in ipairs(name) do local l = name[id][1] local key = name[id][2] if(string.upper(key) == string.upper(sev)) then return(l) end end return(firstToUpper(sev)) end epp_rrd_names = { { "Positive Replies Number", "num_replies_ok.rrd" }, { "Error Replies Number", "num_replies_error.rrd" }, { "Query Number", "num_queries.rrd" }, { "domain-create", "num_cmd_1.rrd" }, { "domain-update", "num_cmd_2.rrd" }, { "domain-delete", "num_cmd_3.rrd" }, { "domain-restore", "num_cmd_4.rrd" }, { "domain-transfer", "num_cmd_5.rrd" }, { "domain-transfer-trade", "num_cmd_6.rrd" }, { "domain-transfer-request", "num_cmd_7.rrd" }, { "domain-transfer-trade-request", "num_cmd_8.rrd" }, { "domain-transfer-cancel", "num_cmd_9.rrd" }, { "domain-transfer-approve", "num_cmd_10.rrd" }, { "domain-transfer-reject", "num_cmd_11.rrd" }, { "contact-create", "num_cmd_12.rrd" }, { "contact-update", "num_cmd_13.rrd" }, { "contact-delete", "num_cmd_14.rrd" }, { "domain-update-hosts", "num_cmd_15.rrd" }, { "domain-update-statuses", "num_cmd_16.rrd" }, { "domain-update-contacts", "num_cmd_17.rrd" }, { "domain-trade", "num_cmd_18.rrd" }, { "domain-update-simple", "num_cmd_19.rrd" }, { "domain-info", "num_cmd_20.rrd" }, { "contact-info", "num_cmd_21.rrd" }, { "domain-check", "num_cmd_22.rrd" }, { "contact-check", "num_cmd_23.rrd" }, { "poll-req", "num_cmd_24.rrd" }, { "domain-transfer-trade-cancel", "num_cmd_25.rrd" }, { "domain-transfer-trade-approve", "num_cmd_26.rrd" }, { "domain-transfer-trade-reject", "num_cmd_27.rrd" }, { "domain-transfer-query", "num_cmd_28.rrd" }, { "login", "num_cmd_29.rrd" }, { "login-chg-pwd", "num_cmd_30.rrd" }, { "logout", "num_cmd_31.rrd" }, { "poll-ack", "num_cmd_32.rrd" }, { "hello", "num_cmd_33.rrd" }, { "unknown-command", "num_cmd_34.rrd" } } function l4Label(proto) return(_handleArray(l4_keys, proto)) end function mapEppRRDName(name) return(_handleArray(epp_rrd_names, name)) end -- Alerts (see ntop_typedefs.h) alert_level_keys = { { "Info", 0 }, { "Warning", 1 }, { "Error", 2 } } alert_type_keys = { { " TCP SYN Flood", 0 }, { " Flows Flood", 1 }, { " Threshold Cross", 2 }, { " Blacklist Host", 3 }, { " Periodic Activity", 4 }, { " Quota Exceeded", 5 } } function alertSeverityLabel(v) return(_handleArray(alert_level_keys, tonumber(v))) end function alertTypeLabel(v) return(_handleArray(alert_type_keys, tonumber(v))) end function firstToUpper(str) str = tostring(str) return (str:gsub("^%l", string.upper)) end function pairsByKeys(t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, f) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function pairsByValues(t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, function(x, y) return f(t[x], t[y]) end) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function asc(a,b) return (a < b) end function rev(a,b) return (a > b) end --for _key, _value in pairsByKeys(vals, rev) do -- print(_key .. "=" .. _value .. "\n") --end function round(num, idp) return tonumber(string.format("%." .. (idp or 0) .. "f", num)) end -- Convert bytes to human readable format function bytesToSize(bytes) precision = 2 kilobyte = 1024; megabyte = kilobyte * 1024; gigabyte = megabyte * 1024; terabyte = gigabyte * 1024; if((bytes >= 0) and (bytes < kilobyte)) then return round(bytes, precision) .. " B"; elseif((bytes >= kilobyte) and (bytes < megabyte)) then return round(bytes / kilobyte, precision) .. ' KB'; elseif((bytes >= megabyte) and (bytes < gigabyte)) then return round(bytes / megabyte, precision) .. ' MB'; elseif((bytes >= gigabyte) and (bytes < terabyte)) then return round(bytes / gigabyte, precision) .. ' GB'; elseif(bytes >= terabyte) then return round(bytes / terabyte, precision) .. ' TB'; else return round(bytes, precision) .. ' B'; end end -- Convert bits to human readable format function bitsToSize(bits) precision = 2 kilobit = 1024; megabit = kilobit * 1024; gigabit = megabit * 1024; terabit = gigabit * 1024; if((bits >= kilobit) and (bits < megabit)) then return round(bits / kilobit, precision) .. ' Kbit/s'; elseif((bits >= megabit) and (bits < gigabit)) then return round(bits / megabit, precision) .. ' Mbit/s'; elseif((bits >= gigabit) and (bits < terabit)) then return round(bits / gigabit, precision) .. ' Gbit/s'; elseif(bits >= terabit) then return round(bits / terabit, precision) .. ' Tbit/s'; else return round(bits, precision) .. ' bps'; end end -- Convert packets to pps readable format function pktsToSize(pkts) precision = 2 if (pkts >= 1000000) then return round(pkts/1000000, precision)..' Mpps'; elseif(pkts >= 1000) then return round(pkts/ 1000, precision)..' Kpps'; else return round(pkts , precision)..' pps'; end end function formatValue(amount) local formatted = amount if(formatted == nil) then return(0) end while true do formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') if(k==0) then break end end return formatted end function formatPackets(amount) return formatValue(amount).." Pkts" end function capitalize(str) return (str:gsub("^%l", string.upper)) end function split(pString, pPattern) local Table = {} -- NOTE: use {n = 0} in Lua-5.0 local fpat = "(.-)" .. pPattern local last_end = 1 local s, e, cap = pString:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(Table,cap) end last_end = e+1 s, e, cap = pString:find(fpat, last_end) end if last_end <= #pString then cap = pString:sub(last_end) table.insert(Table, cap) end return Table end string.split = function(s, p) local temp = {} local index = 0 local last_index = string.len(s) while true do local i, e = string.find(s, p, index) if i and e then local next_index = e + 1 local word_bound = i - 1 table.insert(temp, string.sub(s, index, word_bound)) index = next_index else if index > 0 and index <= last_index then table.insert(temp, string.sub(s, index, last_index)) elseif index == 0 then temp = nil end break end end return temp end function formatEpoch(epoch) return(os.date("%d/%m/%Y %X", epoch)) end function secondsToTime(seconds) if(seconds == nil) then return "" end if(seconds < 1) then return("< 1 sec") end days = math.floor(seconds / 86400) hours = math.floor((seconds / 3600) - (days * 24)) minutes = math.floor((seconds / 60) - (days * 1440) - (hours * 60)) sec = seconds % 60 msg = "" if(days > 0) then years = math.floor(days/365) if(years > 0) then days = days % 365 msg = years .. " year" if(years > 1) then msg = msg .. "s" end msg = msg .. ", " end if(days > 0) then msg = msg .. days .. " day" if(days > 1) then msg = msg .. "s" end msg = msg .. ", " end end if(hours > 0) then msg = msg .. string.format("%d ", hours) if(hours > 1) then msg = msg .. "h" else msg = msg .. "h" end --if(hours > 1) then msg = msg .. "s" end msg = msg .. ", " end if(minutes > 0) then msg = msg .. string.format("%d min", minutes) end if(sec > 0) then if((string.len(msg) > 0) and (minutes > 0)) then msg = msg .. ", " end msg = msg .. string.format("%d sec", sec); end return msg end function starts(String,Start) return string.sub(String,1,string.len(Start))==Start end function ends(String,End) return End=='' or string.sub(String,-string.len(End))==End end -- ################################################################# categories = { {"1_1", "Drug Abuse", { {"Websites that feature information on illegal drug activities including: drug promotion, preparation, cultivation, trafficking, distribution, solicitation, etc."}, }}, {"1_2", "Hacking", { {"Websites that depict illicit activities surrounding the unauthorized modification or access to programs, computers, equipment and websites."}, }}, {"1_3", "Illegal or Unethical", { {"Websites that feature information, methods, or instructions on fraudulent actions or unlawful conduct (non-violent) such as scams, counterfeiting, tax evasion, petty theft, blackmail, etc."}, }}, {"1_4", "Discrimination", { {"Sites that promote the identification of racial groups, the denigration or subjection of groups, or the superiority of any group."}, }}, {"1_5", "Violence", { {"This category includes sites that depict offensive material on brutality, death, cruelty, acts of abuse, mutilation, etc."}, }}, {"1_6", "Proxy Avoidance", { {"Websites that provide information or tools on how to bypass Internet access controls and browse the Web anonymously, includes anonymous proxy servers."}, }}, {"1_7", "Plagiarism", { {"Websites that provide, distribute or sell school essays, projects, or diplomas."}, }}, {"1_8", "Child Abuse", { {"Websites that have been verified by the Internet Watch Foundation to contain or distribute images of non-adult children that are depicted in a state of abuse"}, }}, {"2_1", "Alternative Beliefs", { {"Websites that provide information about or promote religions not specified in Traditional Religions or other unconventional, cultic, or folkloric beliefs and practices. Sites that promote or offer methods, means of instruction, or other resources to affect or influence real events through the use of spells, curses, magic powers, satanic or supernatural beings."}, }}, {"2_2", "Abortion", { {"Websites pertaining to abortion data, information, legal issues, and organizations."}, }}, {"2_3", "Adult Materials", { {"Mature content websites (18+ years and over) that feature or promote sexuality, strip clubs, sex shops, etc. excluding sex education, without the intent to sexually arouse."}, }}, {"2_4", "Advocacy Groups", { {"This category caters to organizations that campaign or lobby for a cause by building public awareness, raising support, influencing public policy, etc."}, }}, {"2_5", "Gambling", { {"Sites that cater to gambling activities such as betting, lotteries, casinos, including gaming information, instruction, and statistics."}, }}, {"2_6", "Extremist Groups", { {"Sites that feature radical militia groups or movements with aggressive anti-government convictions or beliefs."}, }}, {"2_7", "Nudity and Risque", { {"Mature content websites (18+ years and over) that depict the human body in full or partial nudity without the intent to sexually arouse."}, }}, {"2_8", "Pornography", { {"Mature content websites (18+ years and over) which present or display sexual acts with the intent to sexually arouse and excite."}, }}, {"2_9", "Tasteless", { {"Tasteless"}, }}, {"2_10", "Weapons", { {"Websites that feature the legal promotion or sale of weapons such as hand guns, knives, rifles, explosives, etc."}, }}, {"2_11", "Homosexuality", { {"Homosexuality"}, }}, {"2_12", "Marijuana", { {"Sites that provide information about or promote the cultivation, preparation, or use of marijuana."}, }}, {"2_13", "Sex Education", { {"Educational websites that provide information or discuss sex and sexuality, without utilizing pornographic materials."}, }}, {"2_14", "Alcohol", { {"Websites which legally promote or sell alcohol products and accessories."}, }}, {"2_15", "Tobacco", { {"Websites which legally promote or sell tobacco products and accessories."}, }}, {"2_16", "Lingerie and Swimsuit", { {"Websites that utilizes images of semi-nude models in lingerie, undergarments and swimwear for the purpose of selling or promoting such items."}, }}, {"2_17", "Sports Hunting and War Games", { {"Web pages that feature sport hunting, war games, paintball facilities, etc. Includes all related clubs, organizations and groups."}, }}, {"3_1", "Feeware and Software Downloads", { {"Sites whose primary function is to provide freeware and software downloads. Cell phone ringtones/images/games, computer software updates for free downloads are all included in this category."}, }}, {"3_2", "File Sharing and Storage", { {"Websites that permit users to utilize Internet servers to store personal files or for sharing, such as with photos."}, }}, {"3_3", "Streaming Media", { {"Websites that allow the downloading of MP3 or other multimedia files."}, }}, {"3_4", "Peer-to-peer File Sharing", { {"Websites that allow users to share files and data storage between each other."}, }}, {"3_5", "Internet Radio and TV", { {"Websites that broadcast radio or TV communications over the Internet."}, }}, {"3_6", "Internet Telephony", { {"Websites that enable telephone communications over the Internet."}, }}, {"4_1", "Malicious Websites", { {"Sites that host software that is covertly downloaded to a user's machine to collect information and monitor user activity, and sites that are infected with destructive or malicious software, specifically designed to damage, disrupt, attack or manipulate computer systems without the user's consent, such as virus or trojan horse."}, }}, {"4_2", "Phishing", { {"Counterfeit web pages that duplicate legitimate business web pages for the purpose of eliciting financial, personal or other private information from the users."}, }}, {"4_3", "Spam URLs", { {"Websites or webpages whose URLs are found in spam emails. These webpages often advertise sex sites, fraudulent wares, and other potentially offensive materials."}, }}, {"5_1", "Finance and Banking", { {"Financial Data and Services -- Sites that offer news and quotations on stocks, bonds, and other investment vehicles, investment advice, but not online trading. Includes banks, credit unions, credit cards, and insurance. Mortgage/insurance brokers apply here as opposed to Brokerage and Trading."}, }}, {"5_2", "Search Engines and Portals", { {"Sites that support searching the Web, news groups, or indices/directories. Sites of search engines that provide info exclusively for shopping or comparing prices, however, fall in Shopping and Auction."}, }}, {"5_3", "General Organizations", { {"Sites that cater to groups, clubs or organisations of individuals with similar interests, either professional, social, humanitarian or recreational in nature. Social and Affiliation Organizations: Sites sponsored by or that support or offer information about organizations devoted chiefly to socializing or common interests other than philanthropy or professional advancement. Not to be be confused with Advocacy Groups and Political Groups."}, }}, {"5_4", "Business", { {"Sites sponsored by or devoted to business firms, business associations, industry groups, or business in general. Information Technology companies are excluded in this category and fall in Information Technology."}, }}, {"5_5", "Information Technology", { {"Information Technology peripherals and services, cell phone services, cable TV/Internet suppliers."}, }}, {"5_6", "Government and Legal Organizations", { {"Government: Sites sponsored by branches, bureaus, or agencies of any level of government, except for the armed forces, including courts, police institutions, city-level government institutions. Legal Organizations: Sites that discuss or explain laws of various government entities."}, }}, {"5_7", "Armed Forces", { {"Websites related to organized military and armed forces, excluding civil and extreme military organizations."}, }}, {"5_8", "Web Hosting", { {"Sites of organizations that provide hosting services, or top-level domain pages of Web communities."}, }}, {"5_9", "Secure Websites", { {"Sites that institute security measures such as authentication, passwords, registration, etc."}, }}, {"5_10", "Web-based Applications", { {"Sites that mimic desktop applications such as word processing, spreadsheets, and slide-show presentations."}, }}, {"6_1", "Advertising", { {"Sites that provide advertising graphics or other ad content files, including ad servers (domain name often with “ad.” , such as ad.yahoo.com). If a site is mainly for online transactions, it is rated as Shopping and Auctions. Includes pay-to-surf and affiliated advertising programs."}, }}, {"6_2", "Brokerage and Trading", { {"Sites that support active trading of securities and management of investments. Real estate broker does not apply here, and falls within Shopping and Auction. Sites that provide supplier and buyer info/ads do not apply here either since they do not provide trading activities."}, }}, {"6_3", "Games", { {"Sites that provide information about or promote electronic games, video games, computer games, role-playing games, or online games. Includes sweepstakes and giveaways. Sport games are not included in this category, but time consuming mathematic game sites that serve little education purpose are included in this category."}, }}, {"6_4", "Web-based Email", { {"Sites that allow users to utilize electronic mail services."}, }}, {"6_5", "Entertainment", { {"Sites that provide information about or promote motion pictures, non-news radio and television, music and programming guides, books, humor, comics, movie theatres, galleries, artists or review on entertainment, and magazines. Includes book sites that have personal flavor or extra-material by authors to promote the books."}, }}, {"6_6", "Arts and Culture", { {"Websites that cater to fine arts, cultural behaviors and backgrounds including conventions, artwork and paintings, music, languages, customs, etc. Also includes institutions such as museums, libraries and historic sites. Sites that promote historical, cultural heritage of certain area, but not purposely promoting travel."}, }}, {"6_7", "Education", { {"Educational Institutions: Sites sponsored by schools, other educational facilities and non-academic research institutions, and sites that relate to educational events and activities. Educational Materials: Sites that provide information about, sell, or provide curriculum materials. Sites that direct instruction, as well as academic journals and similar publications where scholars and professors submit academic/research articles."}, }}, {"6_8", "Health and Wellness", { {"Sites that provide information or advice on personal health or medical services, procedures, or devices, but not drugs. Includes self-help groups. This category includes cosmetic surgery providers, children's hospitals, but not sites of medical care for pets, which fall in Society and Lifestyle."}, }}, {"6_9", "Job Search", { {"Sites that offer information about or support the seeking of employment or employees. Includes career agents and consulting services that provide job postings."}, }}, {"6_10", "Medicine", { {"Prescribed Medications: Sites that provide information about approved drugs and their medical use. Supplements and Unregulated Compounds: Sites that provide information about or promote the sale or use of chemicals not regulated by the FDA (such as naturally occurring compounds). This category includes sites of online shopping for medicine, as it is a sensitive category separated from regular shopping."}, }}, {"6_11", "News and Media", { {"Sites that offer current news and opinion, including those sponsored by newspapers, general-circulation magazines, or other media. This category includes TV and Radio sites, as long as they are not exclusively for entertainment purpose, but excludes academic journals. Alternative Journals: Online equivalents to supermarket tabloids and other fringe publications."}, }}, {"6_12", "Social Networking", { {"Includes websites that aid in the coordination of heterosexual relationships and companionship. Includes legal and non-sexual sites related to on-line dating, personal ads, dating services, clubs, etc."}, }}, {"6_13", "Political Organizations", { {"Sites that are sponsored by or provide information about political parties and interest groups focused on elections or legislation. This is not to be confused with Government and Legal Organizations, and Advocacy Groups."}, }}, {"6_14", "Reference", { {"Websites that provide general reference data in the form of libraries, dictionaries, thesauri, encyclopedias, maps, directories, standards, etc."}, }}, {"6_15", "Global Religion", { {"Sites that provide information about or promote Buddhism, Bahai, Christianity, Christian Science, Hinduism, Islam, Judaism, Mormonism, Shinto, and Sikhism, as well as atheism."}, }}, {"6_16", "Shopping and Auction", { {"Websites that feature on-line promotion or sale of general goods and services such as electronics, flowers, jewelry, music, etc, excluding real estate. Also includes on-line auction services such as eBay, Amazon, Priceline."}, }}, {"6_17", "Society and Lifestyles", { {"This category contains sites that deal with everyday life issues and preferences such as passive hobbies (gardening, stamp collecting, pets), journals, blogs, etc."}, }}, {"6_18", "Sports Travel", { {"Includes sites that pertain to recreational sports and active hobbies such as fishing, hunting, jogging, canoeing, archery, chess, as well as organized, professional and competitive sports. Websites feature travel related resources such as accommodations, transportation (rail, airlines, cruise ships), agencies, resort locations, tourist attractions, advisories, etc."}, }}, {"6_19", "Personal Vehicles", { {"Websites that contain information on private use or sale of autos, boats, planes, motorcycles, etc., including parts and accessories."}, }}, {"6_20", "Dynamic Content", { {"URLs that are generated dynamically by a Web server."}, }}, {"6_21", "Miscellaneous", { {"This category houses URLs that cannot be definitively categorized due to lack of or ambiguous content."}, }}, {"6_22", "Folklore", { {"UFOs, fortune telling, horoscopes, fen shui, palm reading, tarot reading, and ghost stories."}, }}, {"6_23", "Web Chat", { {"Sites that host Web chat services, or that support or provide information about chat via HTTP or IRC."}, }}, {"6_24", "Instant Messaging", { {"Sites that allow users to communicate in real-time over the Internet."}, }}, {"6_25", "Newsgroups and Message Boards", { {"Sites for online personal and business clubs, discussion groups, message boards, and list servers; includes 'blogs' and 'mail magazines.'"}, }}, {"6_26", "Digital Postcards", { {"Sites for sending/viewing digital post cards."}, }}, {"6_27", "Child Education", { {"Websites developed for children age 12 and under. Includes educational games, tools, organizations and schools. Note that children's hospitals are rated as Health."}, }}, {"6_28", "Real Estate", { {"Websites that promote the sale or renting of real estate properties."}, }}, {"6_29", "Restaurant and Dining", { {"Websites related to restaurants and dining, includes locations, food reviews, recipes, catering services, etc."}, }}, {"6_30", "Personal Websites and Blogs", { {"Private web pages that host personal information, opinions and ideas of the owners."}, }}, {"6_31", "Content Servers", { {"Websites that host servers that distribute content for subscribing websites. Includes image and Web servers."}, }}, {"6_32", "Domain Parking", { {"Sites that simply are place holders of domains without meaningful content."}, }}, {"6_33", "Personal Privacy", { {"Sites providing online banking, trading, health care, and others that contain personal privacy information."}, }}, {"7_0", "Unrated", { {"Unrated site."}, }} }; function getCategory(_cat) if(_cat == nil) then return "" end cat = string.gsub(_cat, "\n", "") if(starts(cat, "error") or (cat == "''") or (cat == "") or starts(cat, "-") or starts(cat, "Local")) then return("") else for id, _ in ipairs(categories) do local key = categories[id][1] local name = categories[id][2] if(key == cat) then return(name) end end return(cat) end end function abbreviateString(str, len) if(str == nil) then return("") else if(string.len(str) < len) then return(str) else return(string.sub(str, 1, len).."...") end end end function bit(p) return 2 ^ (p - 1) -- 1-based indexing end -- Typical call: if hasbit(x, bit(3)) then ... function hasbit(x, p) return x % (p + p) >= p end function setbit(x, p) return hasbit(x, p) and x or x + p end function clearbit(x, p) return hasbit(x, p) and x - p or x end function isBroadMulticast(ip) if(ip == "0.0.0.0") then return(true) end -- print(ip) t = string.split(ip, "%.") -- print(table.concat(t, "\n")) if(t == nil) then return(false) -- Might be an IPv6 address else if(tonumber(t[1]) >= 224) then return(true) end end return(false) end function addGauge(name, url, maxValue, width, height) if(url ~= nil) then print('') end print('\n') -- print('
\n') if(url ~= nil) then print('
') end print [[ \n") end -- Compute the difference in seconds between local time and UTC. function get_timezone() local now = os.time() return os.difftime(now, os.time(os.date("!*t", now))) end function isLocal(host_ip) host = interface.getHostInfo(host_ip) if((host == nil) or (host['localhost'] ~= true)) then return(false) else return(true) end end -- Return the first 'howmany' hosts function getTopInterfaceHosts(howmany, localHostsOnly) hosts_stats = interface.getHostsInfo() ret = {} sortTable = {} n = 0 for k,v in pairs(hosts_stats) do if((not localHostsOnly) or ((v["localhost"] == true) and (v["ip"] ~= nil))) then sortTable[v["bytes.sent"]+v["bytes.rcvd"]+n] = k n = n +0.01 end end n = 0 for _v,k in pairsByKeys(sortTable, rev) do if(n < howmany) then ret[k] = hosts_stats[k] n = n+1 else break end end return(ret) end function http_escape(s) s = string.gsub(s, "([&=+%c])", function (c) return string.format("%%%02X", string.byte(c)) end) s = string.gsub(s, " ", "+") return s end function getInterfaceId(interface_name) ifnames = interface.getIfNames() for _,if_name in pairs(ifnames) do interface.select(if_name) ifstats = interface.getStats() if(ifstats.name == interface_name) then return(ifstats.id) end end return(-1) end -- Windows fixes for interfaces with "uncommon chars" function purifyInterfaceName(interface_name) interface_name = string.gsub(interface_name, "@", "_") interface_name = string.gsub(interface_name, ":", "_") return(interface_name) end -- Fix path format Unix <-> Windows function fixPath(path) if(ntop.isWindows() and (string.len(path) > 2)) then path = string.gsub(path, "/", "\\") -- Avoid changing c:\.... into c_\.... path = string.sub(path, 1, 2) .. string.gsub(string.sub(path, 3), ":", "_") -- io.write("->"..path.."\n") end return(path) end -- See datatype AggregationType in ntop_typedefs.h function aggregation2String(value) if(value == 0) then return("Client Name") elseif(value == 1) then return("Server Name") elseif(value == 2) then return("Domain Name") elseif(value == 3) then return("Operating System") elseif(value == 4) then return("Registrar Name") else return(value) end end function getOSIcon(name) icon = "" if(findString(name, "Linux") or findString(name, "Ubuntu")) then icon = ' ' elseif(findString(name, "Android")) then icon = ' ' elseif(findString(name, "Windows") or findString(name, "Win32") or findString(name, "MSIE")) then icon = ' ' elseif(findString(name, "iPhone") or findString(name, "iPad") or findString(name, "OS X") ) then icon = ' ' end return(icon) end function getApplicationLabel(name) icon = "" if(name == nil) then name = "" end if(findString(name, "Skype")) then icon = '' elseif(findString(name, "Unknown")) then icon = '' elseif(findString(name, "Twitter")) then icon = '' elseif(findString(name, "DropBox")) then icon = '' elseif(findString(name, "Spotify")) then icon = '' elseif(findString(name, "Apple")) then icon = '' elseif(findString(name, "Google") or findString(name, "Chrome")) then icon = '' elseif(findString(name, "FaceBook")) then icon = '' elseif(findString(name, "Youtube")) then icon = '' elseif(findString(name, "thunderbird")) then icon = '' end name = name:gsub("^%l", string.upper) return(icon.." "..name) end function mapOS2Icon(name) if(name == nil) then return("") else return(getOSIcon(name) .. name) end end function getItemsNumber(n) tot = 0 for k,v in pairs(n) do --io.write(k.."\n") tot = tot + 1 end --io.write(tot.."\n") return(tot) end function getHostCommaSeparatedList(p_hosts) hosts = {} hosts_size = 0 for i,host in pairs(split(p_hosts, ",")) do hosts[i] = host hosts_size = hosts_size + 1 end return hosts,hosts_size end -- ############################################## -- Used to avoid resolving host names too many times resolved_host_labels_cache = {} function getHostAltName(host_ip) local alt_name = resolved_host_labels_cache[host_ip] if(alt_name ~= nil) then return(alt_name) end alt_name = ntop.getHashCache("ntopng.host_labels", host_ip) if((alt_name == nil) or (alt_name == "")) then alt_name = host_ip end resolved_host_labels_cache[host_ip] = alt_name return(alt_name) end function setHostAltName(host_ip, alt_name) ntop.setHashCache("ntopng.host_labels", host_ip, alt_name) end -- Flow Utils -- function flowinfo2hostname(flow_info, host_type, show_vlan) local name local orig_name name = flow_info[host_type..".host"] if((name == "") or (name == nil)) then name = flow_info[host_type..".ip"] end orig_name = name name = getHostAltName(name) if(name == orig_name) then rname = ntop.getResolvedAddress(name) if((rname ~= nil) and (rname ~= "")) then name = rname end end -- io.write(host_type.. " / " .. flow_info[host_type..".host"].." / "..name.."\n") if(show_vlan and (flow_info["vlan"] > 0)) then name = name .. '@' .. flow_info["vlan"] end return name end -- Url Util -- -- -- Split the host key (ip@vlan) creating a new lua table. -- Example: -- info = hostkey2hostinfo(key) -- ip = info["host"] -- vlan = info["vlan"] -- function hostkey2hostinfo(key) local host = {} local info = split(key,"@") if(info[1] ~= nil) then host["host"] = info[1] end if(info[2] ~= nil) then host["vlan"] = tonumber(info[2]) else host["vlan"] = 0 end return host end -- -- Analyze the host_info table and return the host key. -- Example: -- host_info = interface.getHostInfo("127.0.0.1",0) -- key = hostinfo2hostkey(host_info) -- function hostinfo2hostkey(host_info,host_type,show_vlan) local rsp = "" if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..host_info["cli.ip"] end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..host_info["srv.ip"] end else if(host_info["host"] ~= nil) then rsp = rsp..host_info["host"] elseif(host_info["name"] ~= nil) then rsp = rsp..host_info["name"] elseif(host_info["ip"] ~= nil) then rsp = rsp..host_info["ip"] elseif(host_info["mac"] ~= nil) then rsp = rsp..host_info["mac"] end end if(((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) or ((show_vlan ~= nil) and show_vlan)) then rsp = rsp..'@'..tostring(host_info["vlan"]) end if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2URL => ".. rsp .. "\n") end return rsp end -- -- Analyze the get_info and return a new table containing the url information about an host. -- Example: url2host(_GET) -- function url2hostinfo(get_info) local host = {} -- Catch when the host key is using as host url parameter if((get_info["host"] ~= nil) and (string.find(get_info["host"],"@"))) then get_info = hostkey2hostinfo(get_info["host"]) end if(get_info["host"] ~= nil) then host["host"] = get_info["host"] if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"URL2HOST => Host:"..get_info["host"].."\n") end end if(get_info["vlan"] ~= nil) then host["vlan"] = tonumber(get_info["vlan"]) if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"URL2HOST => Vlan:"..get_info["vlan"].."\n") end else host["vlan"] = 0 end return host end -- -- Catch the main information about an host from the host_info table and return the corresponding url. -- Example: -- hostinfo2url(host_key), return an url based on the host_key -- hostinfo2url(host[key]), return an url based on the host value -- hostinfo2url(flow[key],"cli"), return an url based on the client host information in the flow table -- hostinfo2url(flow[key],"srv"), return an url based on the server host information in the flow table -- function hostinfo2url(host_info,host_type) local rsp = '' -- local version = 0 local version = 1 if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..'host='..host_info["cli.ip"] end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..'host='..host_info["srv.ip"] end else if((type(host_info) ~= "table")) then host_info = hostkey2hostinfo(host_info) end if(host_info["host"] ~= nil) then rsp = rsp..'host='..host_info["host"] elseif(host_info["ip"] ~= nil) then rsp = rsp..'host='..host_info["ip"] elseif(host_info["name"] ~= nil) then rsp = rsp..'host='..host_info["name"] elseif(host_info["mac"] ~= nil) then rsp = rsp..'host='..host_info["mac"] end end if((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) then if(version == 0) then rsp = rsp..'&vlan='..tostring(host_info["vlan"]) elseif(version == 1) then rsp = rsp..'@'..tostring(host_info["vlan"]) end end if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2URL => ".. rsp .. "\n") end return rsp end -- -- Catch the main information about an host from the host_info table and return the corresponding json. -- Example: -- hostinfo2json(host[key]), return a json string based on the host value -- hostinfo2json(flow[key],"cli"), return a json string based on the client host information in the flow table -- hostinfo2json(flow[key],"srv"), return a json string based on the server host information in the flow table -- function hostinfo2json(host_info,host_type) local rsp = '' if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..'host: "'..host_info["cli.ip"]..'"' end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..'host: "'..host_info["srv.ip"]..'"' end else if((type(host_info) ~= "table") and (string.find(host_info,"@"))) then host_info = hostkey2hostinfo(host_info) end if(host_info["host"] ~= nil) then rsp = rsp..'host: "'..host_info["host"]..'"' elseif(host_info["ip"] ~= nil) then rsp = rsp..'host: "'..host_info["ip"]..'"' elseif(host_info["name"] ~= nil) then rsp = rsp..'host: "'..host_info["name"] ..'"' elseif(host_info["mac"] ~= nil) then rsp = rsp..'host: "'..host_info["mac"] ..'"' end end if((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) then rsp = rsp..', vlan: "'..tostring(host_info["vlan"]) .. '"' end if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2JSON => ".. rsp .. "\n") end return rsp end -- -- Catch the main information about an host from the host_info table and return the corresponding jqueryid. -- Example: host 192.168.1.254, vlan0 ==> 1921681254_0 function hostinfo2jqueryid(host_info,host_type) local rsp = '' if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..''..host_info["cli.ip"] end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..''..host_info["srv.ip"] end else if((type(host_info) ~= "table") and (string.find(host_info,"@"))) then host_info = hostkey2hostinfo(host_info) end if(host_info["host"] ~= nil) then rsp = rsp..''..host_info["host"] elseif(host_info["ip"] ~= nil) then rsp = rsp..''..host_info["ip"] elseif(host_info["name"] ~= nil) then rsp = rsp..''..host_info["name"] elseif(host_info["mac"] ~= nil) then rsp = rsp..''..host_info["mac"] end end if((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) then rsp = rsp..'_'..tostring(host_info["vlan"]) end rsp = string.gsub(rsp, "%.", "__") rsp = string.gsub(rsp, "/", "___") rsp = string.gsub(rsp, ":", "____") if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2KEY => ".. rsp .. "\n") end return rsp end -- version is major.minor.veryminor function version2int(v) if(v == nil) then return(0) end e = string.split(v, "%."); if(e ~= nil) then major = e[1] minor = e[2] veryminor = e[3] if(major == nil or type(major) ~= "number") then major = 0 end if(minor == nil or type(minor) ~= "number") then minor = 0 end if(veryminor == nil or type(veryminor) ~= "number") then veryminor = 0 end version = tonumber(major)*1000 + tonumber(minor)*100 + tonumber(veryminor) return(version) else return(0) end end -- Print contents of `tbl`, with indentation. -- `indent` sets the initial level of indentation. function tprint (tbl, indent) if not indent then indent = 0 end if(tbl ~= nil) then for k, v in pairs(tbl) do formatting = string.rep(" ", indent) .. k .. ": " if type(v) == "table" then io.write(formatting) tprint(v, indent+1) elseif type(v) == 'boolean' then io.write(formatting .. tostring(v)) else io.write(formatting .. v) end end io.write("\n") end end function table.empty(table) if(table == nil) then return true end if next(table) == nil then return true end return false end function table.len(table) local count = 0 if(table == nil) then return(0) end for k,v in pairs(table) do count = count + 1 end return count end -- ############################################ -- Redis Utils -- ############################################ -- Inpur: General prefix (i.e ntopng.pref) -- Output: User based prefix, if it exists -- -- Examples: -- With user: ntopng.pref.user_name -- Without: ntopng.pref function getRedisPrefix(str) if not (isEmptyString(_SESSION["user"] )) then -- Login enabled return (str .. '.' .. _SESSION["user"]) else -- Login disabled return (str) end end function getPathFromKey(key) local path = string.gsub(key, "%.", "/") path = string.gsub(path, ":", "_") return fixPath(path) end ----- End of Redis Utils ------ -- ############################################ -- Runtime preference function prefsInputField(label, comment, key, value) if(_GET[key] ~= nil) then k = "ntopng.prefs."..key v_s = _GET[key] v = tonumber(v_s) if(v ~= nil and (v > 0) and (v < 86400)) then -- print(k.."="..v) ntop.setCache(k, tostring(v)) value = v elseif (v_s ~= nil) then ntop.setCache(k, v_s) value = v_s end end print(''..label..'

'..comment..'') print [[

]] end function toggleTableButton(label, comment, on_label, on_value, on_color , off_label, off_value, off_color, submit_field, redis_key, disabled) if(_GET[submit_field] ~= nil) then ntop.setCache(redis_key, _GET[submit_field]) value = _GET[submit_field] else value = ntop.getCache(redis_key) end if (disabled == true) then disabled = 'disabled = ""' else disabled = "" end -- Read it anyway to if(value == off_value) then rev_value = on_value on_active = "btn-default" off_active = "btn-"..off_color.." active" else rev_value = off_value on_active = "btn-"..on_color.." active" off_active = "btn-default" end if(label ~= "") then print(''..label..'

'..comment..'\n') end print('

\n
') print('\n') print('\n') print('') print('
\n') print('
\n') if(label ~= "") then print('') end return(value) end function isPausedInterface(current_ifname) state = ntop.getCache("ntopng.prefs."..current_ifname.."_not_idle") if(state == "0") then return true else return false end end function getThroughputType() throughput_type = ntop.getCache("ntopng.prefs.thpt_content") if(throughput_type == "") then throughput_type = "bps" end return throughput_type end function isLoopback(name) if((name == "lo") or (name == "lo0")) then return(true) else return(false) end end function processColor(proc) if(proc == nil) then return("") elseif(proc["average_cpu_load"] < 33) then return(""..proc["name"].."") elseif(proc["average_cpu_load"] < 66) then return(""..proc["name"].."") else return(""..proc["name"].."") end end -- Table preferences function getDefaultTableSort(table_type) table_key = getRedisPrefix("ntopng.prefs.table") if(table_type ~= nil) then value = ntop.getHashCache(table_key, "sort_"..table_type) end if((value == nil) or (value == "")) then value = 'column_' end return(value) end function getDefaultTableSortOrder(table_type) table_key = getRedisPrefix("ntopng.prefs.table") if(table_type ~= nil) then value = ntop.getHashCache(table_key, "sort_order_"..table_type) end if((value == nil) or (value == "")) then value = 'desc' end return(value) end function getDefaultTableSize() table_key = getRedisPrefix("ntopng.prefs.table") value = ntop.getHashCache(table_key, "rows_number") if((value == nil) or (value == "")) then value = 10 end return(tonumber(value)) end function tablePreferences(key, value) table_key = getRedisPrefix("ntopng.prefs.table") if((value == nil) or (value == "")) then -- Get preferences return ntop.getHashCache(table_key, key) else -- Set preferences ntop.setHashCache(table_key, key, value) return(value) end end function getHumanReadableInterfaceName(interface_id) key = 'ntopng.prefs.'..interface_id..'.name' custom_name = ntop.getCache(key) if((custom_name ~= nil) and (custom_name ~= "")) then return(custom_name) else interface.select(interface_id) ifstats = interface.getStats() -- print(interface_id.."="..ifstats.name) if((interface_id ~= ifstats.description) and (ifstats.description ~= "PF_RING")) then return(ifstats.description) else return(ifstats.name) end end end function escapeHTML(s) s = string.gsub(s, "([&=+%c])", function (c) return string.format("%%%02X", string.byte(c)) end) s = string.gsub(s, " ", "+") return s end function unescapeHTML (s) s = string.gsub(s, "+", " ") s = string.gsub(s, "%%(%x%x)", function (h) return string.char(tonumber(h, 16)) end) return s end -- ############################################## function harvestUnusedDir(path, min_epoch) local files = ntop.readdir(path) -- print("Reading "..path.."
\n") for k,v in pairs(files) do if(v ~= nil) then local p = fixPath(path .. "/" .. v) if(ntop.isdir(p)) then harvestUnusedDir(p, min_epoch) else local when = ntop.fileLastChange(path) if((when ~= -1) and (when < min_epoch)) then os.remove(p) end end end end end -- ############################################## function harvestJSONTopTalkers(days) local when = os.time() - 86400 * days ifnames = interface.getIfNames() for _,ifname in pairs(ifnames) do interface.select(ifname) local ifstats = interface.getStats() local dirs = ntop.getDirs() local basedir = fixPath(dirs.workingdir .. "/" .. ifstats.id) harvestUnusedDir(fixPath(basedir .. "/top_talkers"), when) harvestUnusedDir(fixPath(basedir .. "/flows"), when) end end -- ############################################## function isAdministrator() local user_group = ntop.getUserGroup() if(user_group == "administrator") then return(true) else return(false) end end -- ############################################## function haveAdminPrivileges() if(isAdministrator) then return(true) else ntop.dumpFile(dirs.installdir .. "/httpdocs/inc/header.inc") dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua") print("
Access forbidden
") return(false) end end -- ############################################## function getKeysSortedByValue(tbl, sortFunction) local keys = {} for key in pairs(tbl) do table.insert(keys, key) end table.sort(keys, function(a, b) return sortFunction(tbl[a], tbl[b]) end) return keys end function getKeys(t, col) local keys = {} for k,v in pairs(t) do keys[tonumber(v[col])] = k end return keys end -- ############################################## function formatBreed(breed) if(breed == "Safe") then return("") elseif(breed == "Acceptable") then return("") elseif(breed == "Fun") then return("") elseif(breed == "Unsafe") then return("") elseif(breed == "Dangerous") then return("") else return("") end end function getFlag(country) if((country == nil) or (country == "")) then return("") else return(" ") end end -- GENERIC UTILS function ternary(cond, T, F) if cond then return T else return F end end -- function split(s, delimiter) result = {}; for match in (s..delimiter):gmatch("(.-)"..delimiter) do table.insert(result, match); end return result; end function strsplit(inputstr, sep) if (inputstr == nil or inputstr == "") then return {} end if sep == nil then sep = "%s" end local t={} ; i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str i = i + 1 end return t end function isempty(array) local count = 0 for _,__ in pairs(array) do count = count + 1 end return (count == 0) end function isin(s, array) if (s == nil or s == "" or array == nil or isempty(array)) then return false end for _, v in pairs(array) do if (s == v) then return true end end return false end function maxRateToString(max_rate) if((max_rate == nil) or (max_rate == "")) then max_rate = -1 end max_rate = tonumber(max_rate) if(max_rate == -1) then return("No Limit") else if(max_rate == 0) then return("Drop All Traffic") else if(max_rate < 1024) then return(max_rate.." Kbps") else local mr mr = round(max_rate / 1024, 2) return(mr.." Mbps") end end end end