edu.uga.cs.fluxbuster.clustering.DomainCluster.java Source code

Java tutorial

Introduction

Here is the source code for edu.uga.cs.fluxbuster.clustering.DomainCluster.java

Source

/*
* Copyright (C) 2012 Chris Neasbitt
* Author: Chris Neasbitt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package edu.uga.cs.fluxbuster.clustering;

import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This class represents a cluster of CandidateFluxDomains.  DomainClusters
 * are the results of hierarchical clustering of CandidateFluxDomains
 * 
 * @author Chris Neasbitt
 */
public class DomainCluster implements Serializable {

    private static final long serialVersionUID = 7189396121418308685L;

    private ArrayList<CandidateFluxDomain> candidateDomains = null;

    private HashSet<String> domains = null;

    private HashSet<InetAddress> ips = null;

    private double ipDiversity = 0;

    private long queries = 0;

    private ArrayList<Double> avgTTLs = null;

    private ArrayList<Double> growthRatios = null;

    private ArrayList<Double> lastGrowthRatioSingleEntries = null;

    private ArrayList<Set<InetAddress>> lastGrowthEntriesIPs = null;

    private ArrayList<Long> lastGrowthEntriesQueries = null;

    private HashSet<InetAddress> lastGrowthClusterIPs = null;

    private long lastGrowthClusterQueries = 0;

    private static Log log = LogFactory.getLog(DomainCluster.class);

    /**
     * Instantiates a new empty domain cluster.
     */
    public DomainCluster() {
        candidateDomains = new ArrayList<CandidateFluxDomain>();
        domains = new HashSet<String>();
        ips = new HashSet<InetAddress>();
        avgTTLs = new ArrayList<Double>();
        growthRatios = new ArrayList<Double>();
        lastGrowthRatioSingleEntries = new ArrayList<Double>();
        lastGrowthClusterIPs = new HashSet<InetAddress>();
        lastGrowthEntriesIPs = new ArrayList<Set<InetAddress>>();
        lastGrowthEntriesQueries = new ArrayList<Long>();
    }

    /**
     * Adds the candidate flux domain to the cluster
     *
     * @param cfd the candidate flux domain to add
     */
    public void addCandidateFluxDomain(CandidateFluxDomain cfd) {
        this.candidateDomains.add(cfd);
        this.domains.add(cfd.getDomainName());
        this.ips.addAll(cfd.getIps());

        // NOTE bases diversity solely on IPv4 addresses
        this.setIpDiversity(IPDiversityCalculator.ipDiversity(IPDiversityCalculator.getV4Ips(ips)));

        this.queries += cfd.getNumQueries();
        this.avgTTLs.add(cfd.getAvgTTL());
        this.growthRatios.add((double) cfd.getNumIPs() / (double) cfd.getNumQueries());

        if (cfd.getLastGrowthRatioSingleEntry() != null) {
            this.lastGrowthRatioSingleEntries.add(cfd.getLastGrowthRatioSingleEntry());
        }

        if (cfd.getLastGrowthEntriesIPs().size() > 0) {
            this.lastGrowthEntriesIPs.add(cfd.getLastGrowthEntriesIPs());
            this.lastGrowthEntriesQueries.add(cfd.getLastGrowthEntriesQueries());
        }

        if (this.candidateDomains.size() > 1) {
            Collections.sort(this.candidateDomains, new Comparator<CandidateFluxDomain>() {
                @Override
                public int compare(CandidateFluxDomain arg0, CandidateFluxDomain arg1) {
                    return arg0.getLastSeen().compareTo(arg1.getLastSeen());
                }
            });

            HashSet<InetAddress> prevIps = new HashSet<InetAddress>();
            for (int i = 0; i < this.candidateDomains.size() - 1; i++) {
                prevIps.addAll(this.candidateDomains.get(i).getIps());
            }
            CandidateFluxDomain lastCFD = this.candidateDomains.get(this.candidateDomains.size() - 1);
            HashSet<InetAddress> temp = new HashSet<InetAddress>();

            temp.addAll(lastCFD.getIps());
            temp.removeAll(prevIps);

            this.lastGrowthClusterIPs = temp;
            this.lastGrowthClusterQueries = lastCFD.getNumQueries();
        }
    }

    /**
     * Gets the queries per domain of the cluster.
     *
     * @return the queries per domain
     */
    public double getQueriesPerDomain() {
        return this.queries / (double) this.domains.size();
    }

    /**
     * Gets the last growth prefix ratio of the cluster.
     *
     * @return the last growth prefix ratio or null if the
     *       feature can not be calculated
     */
    public Double getLastGrowthPrefixRatioCluster() {
        if (lastGrowthClusterIPs.size() > 0) {
            return getPrefixes24(lastGrowthClusterIPs).size() / (double) lastGrowthClusterQueries;
        } else {
            return null;
        }
    }

    /**
     * Gets the last growth ratio of the cluster.
     *
     * @return the last growth ratio or null if the feature
     *       can not be calculated
     */
    public Double getLastGrowthRatioCluster() {
        if (lastGrowthClusterIPs.size() > 0) {
            return lastGrowthClusterIPs.size() / (double) lastGrowthClusterQueries;
        } else {
            return null;
        }
    }

    /**
     * Gets the avg last growth ratio single entry feature 
     * of the cluster
     *
     * @return the avg last growth ratio single entry or null
     *       if the feature can not be calculated
     */
    public Double getAvgLastGrowthRatioSingleEntry() {
        if (lastGrowthRatioSingleEntries.size() > 0) {
            double temp = 0;
            for (double d : lastGrowthRatioSingleEntries) {
                temp += d;
            }
            return temp / lastGrowthRatioSingleEntries.size();
        } else {
            return null;
        }
    }

    /**
     * Gets the last growth ratio entries list of the cluster.
     *
     * @return the list of last growth ratio entries
     */
    private List<Double> getLastGrowthRatioEntriesList() {
        ArrayList<Double> retval = new ArrayList<Double>();
        if (lastGrowthEntriesIPs.size() > 0) {
            for (int i = 0; i < lastGrowthEntriesIPs.size(); i++) {
                retval.add(lastGrowthEntriesIPs.get(i).size() / (double) lastGrowthEntriesQueries.get(i));
            }
        }
        return retval;
    }

    /**
     * Gets the last growth prefix ratio entries list of the cluster.
     *
     * @return the list of last growth prefix ratio entries
     */
    private List<Double> getLastGrowthPrefixRatioEntriesList() {
        ArrayList<Double> retval = new ArrayList<Double>();
        if (lastGrowthEntriesIPs.size() > 0) {
            for (int i = 0; i < lastGrowthEntriesIPs.size(); i++) {
                retval.add(getPrefixes24(lastGrowthEntriesIPs.get(i)).size()
                        / (double) lastGrowthEntriesQueries.get(i));
            }
        }
        return retval;
    }

    /**
     * Gets the cluster's average last growth ratio entries.
     *
     * @return the average last growth ratio entries
     */
    public Double getAvgLastGrowthRatioEntries() {
        List<Double> list = getLastGrowthRatioEntriesList();
        if (list.size() > 0) {
            double temp = 0;
            for (double d : list) {
                temp += d;
            }
            return temp / list.size();
        } else {
            return null;
        }
    }

    /**
     * Gets the cluster's average last growth prefix ratio entries.
     *
     * @return the average last growth prefix ratio entries
     */
    public Double getAvgLastGrowthPrefixRatioEntries() {
        List<Double> list = getLastGrowthPrefixRatioEntriesList();
        if (list.size() > 0) {
            double temp = 0;
            for (double d : list) {
                temp += d;
            }
            return temp / list.size();
        } else {
            return null;
        }
    }

    /**
     * Gets the candidate flux domains in the cluster.
     *
     * @return the list of candidate flux domains
     */
    public List<CandidateFluxDomain> getCandidateDomains() {
        ArrayList<CandidateFluxDomain> retval = new ArrayList<CandidateFluxDomain>();
        retval.addAll(candidateDomains);
        return retval;
    }

    /**
     * Sets the cluster's candidate flux domains.
     *
     * @param candidateDomains the list of candidate flux domains
     */
    public void setCandidateDomains(List<CandidateFluxDomain> candidateDomains) {
        this.candidateDomains.clear();
        this.candidateDomains.addAll(candidateDomains);
    }

    /**
     * Gets the domain names in the cluster.
     *
     * @return the set of domain names
     */
    public Set<String> getDomains() {
        HashSet<String> retval = new HashSet<String>();
        retval.addAll(this.domains);
        return retval;
    }

    /**
     * Sets the domain names in the cluster.
     *
     * @param domains the set of domains
     */
    public void setDomains(Set<String> domains) {
        this.domains.clear();
        this.domains.addAll(domains);
    }

    /**
     * Gets the set of IP addresses in the cluster.
     *
     * @return the set of the IP addresses
     */
    public Set<InetAddress> getIps() {
        HashSet<InetAddress> retval = new HashSet<InetAddress>();
        retval.addAll(this.ips);
        return retval;
    }

    /**
     * Sets the IP addresses in the cluster.
     *
     * @param ips the set of the IP addresses
     */
    public void setIps(Set<InetAddress> ips) {
        this.ips.clear();
        this.ips.addAll(ips);
    }

    /**
     * Gets the ip diversity of the cluster.
     *
     * @return the ip diversity
     */
    public double getIpDiversity() {
        return ipDiversity;
    }

    /**
     * Sets the ip diversity of the cluster.
     *
     * @param ipDiversity the ip diversity
     */
    public void setIpDiversity(double ipDiversity) {
        this.ipDiversity = ipDiversity;
    }

    /**
     * Gets the number of dns queries in the cluster.
     *
     * @return the number of dns queries
     */
    public long getQueries() {
        return queries;
    }

    /**
     * Sets the number of dns queries in the cluster.
     *
     * @param queries the number of dns queries
     */
    public void setQueries(long queries) {
        this.queries = queries;
    }

    /**
     * Gets the list of average ttls in the cluster.
     *
     * @return the list average ttls
     */
    public List<Double> getAvgTTLs() {
        return avgTTLs;
    }

    /**
     * Gets the average ttl per domain of the cluster.
     * 
     * @return the avergae ttl
     */

    public double getAvgTTLPerDomain() {
        List<Double> ttls = this.getAvgTTLs();
        double ttl_per_domain = 0;
        if (ttls.size() > 0) {
            double temp = 0.0;
            for (double ttl : ttls) {
                temp += ttl;
            }
            ttl_per_domain = temp / ttls.size();
        }
        return ttl_per_domain;
    }

    /**
     * Sets the list of average ttls in the cluster.
     *
     * @param avgTTLs the cluster's average ttls
     */
    public void setAvgTTLs(ArrayList<Double> avgTTLs) {
        this.avgTTLs = avgTTLs;
    }

    /**
     * Gets the growth ratios for the cluster.
     *
     * @return the list of growth ratios
     */
    public List<Double> getGrowthRatios() {
        ArrayList<Double> retval = new ArrayList<Double>();
        retval.addAll(this.growthRatios);
        return retval;
    }

    public double getIpGrowthRatio() {
        List<Double> ratios = this.getGrowthRatios();
        double ip_growth_ratio = 0;
        if (ratios.size() > 0) {
            double temp = 0.0;
            for (double ratio : ratios) {
                temp += ratio;
            }
            ip_growth_ratio = temp / ratios.size();
        }
        return ip_growth_ratio;
    }

    /**
     * Sets the growth ratios for the cluster.
     *
     * @param growthRatios the list growth ratios
     */
    public void setGrowthRatios(List<Double> growthRatios) {
        this.growthRatios.clear();
        this.growthRatios.addAll(growthRatios);
    }

    /**
     * Gets the last growth ratio single entries feature for
     * this cluster.
     *
     * @return the list of last growth ratio single entries
     */
    public List<Double> getLastGrowthRatioSingleEntries() {
        ArrayList<Double> retval = new ArrayList<Double>();
        retval.addAll(this.lastGrowthRatioSingleEntries);
        return retval;
    }

    /**
     * Sets the last growth ratio single entries feature for
     * this cluster.
     *
     * @param lastGrowthRatioSingleEntries the list of last growth 
     *       ratio single entries
     */
    public void setLastGrowthRatioSingleEntries(List<Double> lastGrowthRatioSingleEntries) {
        this.lastGrowthRatioSingleEntries.clear();
        this.lastGrowthRatioSingleEntries.addAll(lastGrowthRatioSingleEntries);
    }

    /**
     * Returns a string representing this DomainCluster.
     * 
     * @return a string representing this DomainCluster.
     */
    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();

        ArrayList<String> domains = new ArrayList<String>();
        HashSet<InetAddress> ipset = new HashSet<InetAddress>();
        ArrayList<InetAddress> ips = new ArrayList<InetAddress>();
        for (CandidateFluxDomain cfd : this.getCandidateDomains()) {
            domains.add(cfd.getDomainName());
            ipset.addAll(cfd.getIps());
        }
        ips.addAll(ipset);
        Collections.sort(domains);
        Collections.sort(ips, new InetAddressComparator());

        buf.append("Domains: \n");
        for (String domain : domains) {
            buf.append("\t" + domain + "\n");
        }

        buf.append("IP's: \n");
        for (InetAddress ip : ips) {
            buf.append("\t" + ip.getHostAddress() + "\n");
        }

        buf.append("Query Volume: " + this.getQueries() + "\n");
        buf.append("Distinct IPs: " + this.getIps().size() + "\n");
        buf.append("IP Diversity: " + this.getIpDiversity() + "\n");

        double sumAvgTTL = 0.0;
        for (double avgTTL : this.getAvgTTLs()) {
            sumAvgTTL += avgTTL;
        }
        buf.append("Average TTL: " + sumAvgTTL / this.getAvgTTLs().size() + "\n");

        double sumGrowthRatios = 0.0;
        for (double growthRatio : this.getGrowthRatios()) {
            sumGrowthRatios += growthRatio;
        }
        buf.append("Average Growth Ratio: " + sumGrowthRatios / this.getGrowthRatios().size() + "\n");

        buf.append("Candidate Flux Domains:\n");
        for (CandidateFluxDomain d : this.getCandidateDomains()) {
            buf.append(d.toString());
        }

        return buf.toString();
    }

    /**
     * Gets the CIDR /24 prefixes of a set of IPv4 addresses
     *
     * @param ips the set of ip addresses
     * @return the set of /24 prefixes
     */
    private Set<InetAddress> getPrefixes24(Set<InetAddress> ips) {
        HashSet<InetAddress> retval = new HashSet<InetAddress>();
        Set<Inet4Address> ipsv4 = IPDiversityCalculator.getV4Ips(ips);
        for (Inet4Address ip : ipsv4) {
            byte[] temp = ip.getAddress();
            temp[3] = 0;
            try {
                retval.add(InetAddress.getByAddress(temp));
            } catch (UnknownHostException e) {
                if (log.isErrorEnabled()) {
                    log.error("Error getting CIDR /24 prefix", e);
                }
            }
        }
        return retval;
    }

}