package com.limegroup.gnutella.filters; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.limewire.core.settings.FilterSettings; import org.limewire.util.Visitor; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.inject.name.Named; import com.limegroup.gnutella.Response; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.QueryReply; import com.limegroup.gnutella.spam.SpamManager; /** * A filter that checks query responses, query replies and individual URNs * against a URN blacklist. */ @Singleton class URNFilterImpl implements URNFilter { private static final Log LOG = LogFactory.getLog(URNFilterImpl.class); private final SpamManager spamManager; private final URNBlacklistManager urnBlacklistManager; private final ScheduledExecutorService backgroundExecutor; private ImmutableSet<String> blacklist = null; @Inject URNFilterImpl(SpamManager spamManager, URNBlacklistManager urnBlacklistManager, @Named("backgroundExecutor") ScheduledExecutorService backgroundExecutor) { this.spamManager = spamManager; this.urnBlacklistManager = urnBlacklistManager; this.backgroundExecutor = backgroundExecutor; } /** * Reloads the blacklist in a different thread and informs the callback, * unless the callback is null. */ @Override public void refreshURNs(final LoadCallback callback) { LOG.debug("Refreshing URN filter"); backgroundExecutor.execute(new Runnable() { @Override public void run() { final ImmutableSet.Builder<String> builder = ImmutableSet.builder(); // 1. Local setting for(String s : FilterSettings.FILTERED_URNS_LOCAL.get()) builder.add(s); // 2. Remote setting if(FilterSettings.USE_NETWORK_FILTER.getValue()) { for(String s : FilterSettings.FILTERED_URNS_REMOTE.get()) builder.add(s); } // 3. File urnBlacklistManager.loadURNs(new Visitor<String>() { @Override public boolean visit(String s) { builder.add(s); return true; } }); blacklist = builder.build(); if(LOG.isDebugEnabled()) LOG.debug("Filter contains " + blacklist.size() + " URNs"); if(callback != null) callback.spamFilterLoaded(); } }); } /** * Returns false if the message is a query reply with a URN that matches * the blacklist; matching query replies are passed to the spam filter. * Returns true for all other messages. */ @Override public boolean allow(Message m) { if(blacklist == null) return true; if(m instanceof QueryReply) { QueryReply q = (QueryReply)m; if(isBlacklisted(q)) { if(FilterSettings.FILTERED_URNS_ARE_SPAM.getValue()) spamManager.handleSpamQueryReply(q); return false; } } return true; } /** * Returns true if any response in the query reply matches the blacklist. * Unlike <code>allow(Message)</code>, matching query replies are not * passed to the spam filter. */ @Override public boolean isBlacklisted(QueryReply q) { if(blacklist == null) return false; try { for(Response r : q.getResultsArray()) { for(URN u : r.getUrns()) { if(isBlacklisted(u)) return true; } } return false; } catch(BadPacketException bpe) { return true; } } /** * Returns true if the given URN matches the blacklist. */ @Override public boolean isBlacklisted(URN urn) { if(blacklist == null) return false; if(blacklist.contains(urn.getNamespaceSpecificString())) { if(LOG.isDebugEnabled()) LOG.debug(urn + " is spam"); return true; } return false; } /** * Returns the blacklisted URNs as base32-encoded strings. For testing. */ @Override public Set<String> getBlacklist() { return blacklist; } }