/* * Data Hub Service (DHuS) - For Space data distribution. * Copyright (C) 2013,2014,2015 GAEL Systems * * This file is part of DHuS software sources. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package fr.gael.dhus.server.http.valve; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import java.util.Map.Entry; import java.util.UUID; public class AbuseMetrics { private Long period; private Long calls; private Map<String, Long>abusiveUsers; private Map<String, Long> abusiveIp; private Map<String, Long> abusiveRequests; /** * @return the period */ public Long getPeriod() { return period; } /** * @param period the period to set */ public void setPeriod(Long period) { this.period = period; } /** * @return the calls */ public Long getCalls() { return calls; } /** * @param calls the calls to set */ public void setCalls(Long calls) { this.calls = calls; } /** * @return the abusiveUsers */ public Map<String, Long> getAbusiveUsers() { return abusiveUsers; } /** * @param abusiveUsers the abusiveUsers to set */ public void setAbusiveUsers(Map<String, Long> abusiveUsers) { this.abusiveUsers = abusiveUsers; } /** * @return the abusiveIp */ public Map<String, Long> getAbusiveIp() { return abusiveIp; } /** * @param abusiveIp the abusiveIp to set */ public void setAbusiveIp(Map<String, Long> abusiveIp) { this.abusiveIp = abusiveIp; } public Map<String, Long> getAbusiveRequests() { return abusiveRequests; } public void setAbusiveRequests(Map<String, Long> abusiveRequests) { this.abusiveRequests = abusiveRequests; } private static String UNKNOWN_USER = "@unknown@"; private static String UNKNOWN_IP="0.0.0.0"; /** * Computes Abusive information metrics from collected access information. * @param requests access informations * @param top number of max values to be retained * @return the metrics of abusive accesses. */ static AbuseMetrics computeAbuseMetricsFromAccess ( Map<UUID,AccessInformation> requests, int skip, int top) { AbuseMetrics abuse = new AbuseMetrics(); Map<String, Long> user_map=new TreeMap<String, Long>(); Map<String, Long> ip_map=new TreeMap<String, Long>(); Map<String, Long> requests_map=new TreeMap<String, Long>(); SortedSet<Entry<UUID, AccessInformation>> accesses= entriesSortedByValues(requests); Iterator<Map.Entry<UUID, AccessInformation>>iterator=accesses.iterator(); long newest=Long.MIN_VALUE; long oldest=Long.MAX_VALUE; long longest_request = Long.MIN_VALUE; long count = 0; while (iterator.hasNext()) { if (skip-->0) continue; Map.Entry<UUID, AccessInformation>entry = iterator.next(); AccessInformation ai = entry.getValue(); // Case of eviction happened. if (ai == null) continue; // Keep track of the delay Long timestamp = ai.getStartTimestamp(); long delay = ai.getDurationNs(); if (timestamp>newest) newest=timestamp; if (timestamp<oldest) oldest=timestamp; if (longest_request<delay) longest_request=delay; // Keep track of the record number count++; // Keep track of the user list long user_count = 1; String username = ai.getUsername(); if (username == null) username=UNKNOWN_USER; if (user_map.containsKey(username)) user_count+=user_map.get(username); user_map.put(username, user_count); // Keep track of the Ip List long ip_count = 1; String ip = ai.getRemoteAddress(); if (ip == null) ip=UNKNOWN_IP; if (ip_map.containsKey(ip)) ip_count += ip_map.get(ip); ip_map.put(ip, ip_count); // Keep track of the request time spent. String request = ai.getRequest(); Long old_request=Long.MIN_VALUE; if (request == null) continue; if (requests_map.containsKey(request)) old_request = requests_map.get(request); if (delay>old_request) requests_map.put(request, delay); } // report the period nanoseconds abuse.setPeriod(newest-oldest); abuse.setCalls(count); // Sort Abusive users SortedSet<Map.Entry<String, Long>> sorted_users_calls = entriesSortedByValues(user_map); Iterator<Map.Entry<String, Long>>user_it=sorted_users_calls.iterator(); abuse.setAbusiveUsers(new LinkedHashMap<String, Long>()); int top_count = 0; while (user_it.hasNext() && top_count++<top) { Map.Entry<String, Long>entry = user_it.next(); abuse.getAbusiveUsers().put(entry.getKey(), entry.getValue()); } // Sort Abusive IP usage SortedSet<Map.Entry<String, Long>> sorted_ip_calls = entriesSortedByValues(ip_map); Iterator<Map.Entry<String, Long>>ip_it=sorted_ip_calls.iterator(); abuse.setAbusiveIp(new LinkedHashMap<String, Long>()); top_count = 0; while (ip_it.hasNext() && top_count++<top) { Map.Entry<String, Long>entry = ip_it.next(); abuse.getAbusiveIp().put(entry.getKey(), entry.getValue()); } // Sort Abusive IP usage SortedSet<Map.Entry<String, Long>> sorted_requests_calls = entriesSortedByValues(requests_map); Iterator<Map.Entry<String, Long>>requests_it= sorted_requests_calls.iterator(); abuse.setAbusiveRequests(new LinkedHashMap<String, Long>()); top_count = 0; while (requests_it.hasNext() && top_count++<top) { Map.Entry<String, Long>entry = requests_it.next(); abuse.getAbusiveRequests().put(entry.getKey(), entry.getValue()); } return abuse; } static <K,V extends Comparable<? super V>> SortedSet <Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) { SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>( new Comparator<Map.Entry<K,V>>() { @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) { int res = e2.getValue().compareTo(e1.getValue()); return res != 0 ? res : 1; } }); sortedEntries.addAll(map.entrySet()); return sortedEntries; } @Override public String toString() { String user_list = "["; String separator=""; for (String user:getAbusiveUsers().keySet()) { user_list += separator + user + ":" + getAbusiveUsers().get(user); separator=","; } user_list+="]"; String ip_list = "["; separator=""; for (String ip:getAbusiveIp().keySet()) { ip_list += separator + ip + ":" + getAbusiveIp().get(ip); separator=","; } ip_list+="]"; String requests_list = "["; separator=""; for (String request:getAbusiveRequests().keySet()) { requests_list += separator + request + ":" + AccessValve. twoDigit(getAbusiveRequests().get(request)/1000000000.0) + "s"; separator=","; } requests_list+="]"; return "Calls=" + this.getCalls() + ", period=" + AccessValve. twoDigit(getPeriod()/1000000000.0).trim() + "s," + user_list + ", " + ip_list + ", " + requests_list; } }