Java tutorial
/* * This file is part of SPFBL. * * SPFBL 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 3 of the License, or * (at your option) any later version. * * SPFBL 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 SPFBL. If not, see <http://www.gnu.org/licenses/>. */ package net.spfbl.data; import net.spfbl.core.Reverse; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeMap; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.spfbl.core.Client; import net.spfbl.core.Core; import net.spfbl.core.Peer; import net.spfbl.core.ProcessException; import net.spfbl.core.Server; import net.spfbl.core.User; import net.spfbl.spf.SPF; import net.spfbl.whois.Domain; import net.spfbl.whois.Owner; import net.spfbl.whois.Subnet; import net.spfbl.whois.SubnetIPv4; import net.spfbl.whois.SubnetIPv6; import org.apache.commons.lang3.SerializationUtils; /** * Representa a lista de bloqueio do sistema. * * @author Leandro Carlos Rodrigues <leandro@spfbl.net> */ public class Block { /** * Flag que indica se o cache foi modificado. */ private static boolean CHANGED = false; /** * Conjunto de remetentes bloqueados. */ private static class SET { private static final HashMap<String, Long> MAP = new HashMap<String, Long>(); public static synchronized boolean isEmpty() { return MAP.isEmpty(); } public static synchronized void clear() { MAP.clear(); } public static TreeSet<String> get(User user) { if (user == null) { return get((String) null); } else { return get(user.getEmail()); } } public static TreeSet<String> get(String user) { TreeSet<String> resultSet = new TreeSet<String>(); for (String token : getAll()) { if (user == null && !token.contains(":")) { resultSet.add(token); } else if (user != null && token.startsWith(user + ':')) { int index = token.indexOf(':'); resultSet.add(token.substring(index + 1)); } } return resultSet; } public static int getAll(OutputStream outputStream) throws Exception { int count = 0; for (String token : getAll()) { outputStream.write(token.getBytes("UTF-8")); outputStream.write('\n'); count++; } return count; } public static synchronized TreeMap<String, Long> getMap() { TreeMap<String, Long> map = new TreeMap<String, Long>(); map.putAll(MAP); return map; } public static synchronized TreeSet<String> getAll() { TreeSet<String> set = new TreeSet<String>(); set.addAll(MAP.keySet()); return set; } private static synchronized void putExact(String token, Long last) { MAP.put(token, last); } private static synchronized boolean addExact(String token) { return MAP.put(token, System.currentTimeMillis()) == null; } private static synchronized boolean dropExact(String token) { return MAP.remove(token) != null; } public static synchronized boolean contains(String token) { if (MAP.containsKey(token)) { MAP.put(token, System.currentTimeMillis()); return CHANGED = true; } else { return false; } } } /** * Conjunto de critperios WHOIS para bloqueio. */ private static class WHOIS { private static final HashMap<String, TreeSet<String>> MAP = new HashMap<String, TreeSet<String>>(); public static synchronized boolean isEmpty() { return MAP.isEmpty(); } public static synchronized void clear() { MAP.clear(); } public static TreeSet<String> get(User user) { if (user == null) { return get((String) null); } else { return get(user.getEmail()); } } public static synchronized TreeSet<String> get(String user) { TreeSet<String> resultSet = new TreeSet<String>(); TreeSet<String> whoisSet = MAP.get(user); if (whoisSet != null) { for (String whois : whoisSet) { resultSet.add("WHOIS/" + whois); } } return resultSet; } public static synchronized int getAll(OutputStream outputStream) throws Exception { int count = 0; for (String client : MAP.keySet()) { for (String whois : MAP.get(client)) { if (client != null) { outputStream.write(client.getBytes("UTF-8")); outputStream.write(':'); } outputStream.write("WHOIS/".getBytes("UTF-8")); outputStream.write(whois.getBytes("UTF-8")); outputStream.write('\n'); count++; } } return count; } public static synchronized TreeSet<String> getAll() { TreeSet<String> set = new TreeSet<String>(); for (String client : MAP.keySet()) { for (String whois : MAP.get(client)) { if (client == null) { set.add("WHOIS/" + whois); } else { set.add(client + ":WHOIS/" + whois); } } } return set; } private static synchronized boolean dropExact(String token) { int index = token.indexOf('/'); String whois = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } TreeSet<String> set = MAP.get(client); if (set == null) { return false; } else { boolean removed = set.remove(whois); if (set.isEmpty()) { MAP.remove(client); } return removed; } } private static synchronized boolean addExact(String client, String token) { int index = token.indexOf('/'); String whois = token.substring(index + 1); TreeSet<String> set = MAP.get(client); if (set == null) { set = new TreeSet<String>(); MAP.put(client, set); } return set.add(whois); } private static synchronized boolean addExact(String token) { int index = token.indexOf('/'); String whois = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } TreeSet<String> set = MAP.get(client); if (set == null) { set = new TreeSet<String>(); MAP.put(client, set); } return set.add(whois); } private static synchronized TreeSet<String> getClientSet(String client) { return MAP.get(client); } public static boolean contains(String client, String host) { if (host == null) { return false; } else { TreeSet<String> whoisSet = getClientSet(client); if (whoisSet == null) { return false; } else { return whoisSet.contains(host); } } } private static String get(String client, Set<String> tokenSet, boolean autoBlock) { if (tokenSet.isEmpty()) { return null; } else { TreeSet<String> subSet = new TreeSet<String>(); TreeSet<String> whoisSet = getClientSet(null); if (whoisSet != null) { subSet.addAll(whoisSet); } if (client != null) { whoisSet = getClientSet(client); if (whoisSet != null) { for (String whois : whoisSet) { subSet.add(client + ':' + whois); } } } if (subSet.isEmpty()) { return null; } else { for (String whois : subSet) { try { char signal = '='; int indexValue = whois.indexOf(signal); if (indexValue == -1) { signal = '<'; indexValue = whois.indexOf(signal); if (indexValue == -1) { signal = '>'; indexValue = whois.indexOf(signal); } } if (indexValue != -1) { String userLocal = null; int indexUser = whois.indexOf(':'); if (indexUser > 0 && indexUser < indexValue) { userLocal = whois.substring(0, indexUser); } String key = whois.substring(indexUser + 1, indexValue); String criterion = whois.substring(indexValue + 1); whois = indexUser == -1 ? whois : whois.substring(indexUser + 1, whois.length()); for (String token : tokenSet) { String value = null; if (Subnet.isValidIP(token)) { value = Subnet.getValue(token, key); } else if (token.startsWith(".") && Domain.isHostname(token)) { value = Domain.getValue(token, key); } else if (!token.startsWith(".") && Domain.isHostname(token.substring(1))) { value = Domain.getValue(token, key); } if (value != null) { if (signal == '=') { if (criterion.equals(value)) { if (autoBlock && (token = addDomain(userLocal, token)) != null) { if (userLocal == null) { Server.logDebug("new BLOCK '" + token + "' added by 'WHOIS/" + whois + "'."); Peer.sendBlockToAll(token); } else { Server.logDebug("new BLOCK '" + userLocal + ":" + token + "' added by '" + userLocal + ":WHOIS/" + whois + "'."); } } if (userLocal == null) { return "WHOIS/" + whois; } else { return userLocal + ":WHOIS/" + whois; } } } else if (value.length() > 0) { int criterionInt = parseIntWHOIS(criterion); int valueInt = parseIntWHOIS(value); if (signal == '<' && valueInt < criterionInt) { if (autoBlock && (token = addDomain(userLocal, token)) != null) { if (userLocal == null) { Server.logDebug("new BLOCK '" + token + "' added by 'WHOIS/" + whois + "'."); Peer.sendBlockToAll(token); } else { Server.logDebug("new BLOCK '" + userLocal + ":" + token + "' added by '" + userLocal + ":WHOIS/" + whois + "'."); } } if (userLocal == null) { return "WHOIS/" + whois; } else { return userLocal + ":WHOIS/" + whois; } } else if (signal == '>' && valueInt > criterionInt) { if (autoBlock && (token = addDomain(userLocal, token)) != null) { if (userLocal == null) { Server.logDebug("new BLOCK '" + token + "' added by 'WHOIS/" + whois + "'."); Peer.sendBlockToAll(token); } else { Server.logDebug("new BLOCK '" + userLocal + ":" + token + "' added by '" + userLocal + ":WHOIS/" + whois + "'."); } } if (userLocal == null) { return "WHOIS/" + whois; } else { return userLocal + ":WHOIS/" + whois; } } } } } } } catch (Exception ex) { Server.logError(ex); } } return null; } } } } /** * Conjunto de DNSBL para bloqueio de IP. */ private static class DNSBL { private static final HashMap<String, TreeSet<String>> MAP = new HashMap<String, TreeSet<String>>(); public static synchronized boolean isEmpty() { return MAP.isEmpty(); } public static synchronized void clear() { MAP.clear(); } public static TreeSet<String> get(User user) { if (user == null) { return get((String) null); } else { return get(user.getEmail()); } } public static synchronized TreeSet<String> get(String user) { TreeSet<String> resultSet = new TreeSet<String>(); TreeSet<String> dnsblSet = MAP.get(user); if (dnsblSet != null) { for (String dnsbl : dnsblSet) { resultSet.add("DNSBL=" + dnsbl); } } return resultSet; } public static synchronized int getAll(OutputStream outputStream) throws Exception { int count = 0; for (String client : MAP.keySet()) { for (String dnsbl : MAP.get(client)) { if (client != null) { outputStream.write(client.getBytes("UTF-8")); outputStream.write(':'); } outputStream.write("DNSBL=".getBytes("UTF-8")); outputStream.write(dnsbl.getBytes("UTF-8")); outputStream.write('\n'); count++; } } return count; } public static synchronized TreeSet<String> getAll() { TreeSet<String> set = new TreeSet<String>(); for (String client : MAP.keySet()) { for (String dnsbl : MAP.get(client)) { if (client == null) { set.add("DNSBL=" + dnsbl); } else { set.add(client + ":DNSBL=" + dnsbl); } } } return set; } private static synchronized boolean dropExact(String token) { int index = token.indexOf('='); String dnsbl = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } TreeSet<String> set = MAP.get(client); if (set == null) { return false; } else { boolean removed = set.remove(dnsbl); if (set.isEmpty()) { MAP.remove(client); } return removed; } } private static synchronized boolean addExact(String client, String token) { int index = token.indexOf('='); String dnsbl = token.substring(index + 1); TreeSet<String> set = MAP.get(client); if (set == null) { set = new TreeSet<String>(); MAP.put(client, set); } return set.add(dnsbl); } private static synchronized boolean addExact(String token) { int index = token.indexOf('='); String dnsbl = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } TreeSet<String> set = MAP.get(client); if (set == null) { set = new TreeSet<String>(); MAP.put(client, set); } return set.add(dnsbl); } public static synchronized boolean contains(String client, String dnsbl) { if (dnsbl == null) { return false; } else { TreeSet<String> dnsblSet = MAP.get(client); if (dnsblSet == null) { return false; } else { return dnsblSet.contains(dnsbl); } } } private static synchronized TreeSet<String> getClientSet(String client) { return MAP.get(client); } private static String get(String client, String ip) { if (ip == null) { return null; } else { TreeMap<String, TreeSet<String>> dnsblMap = new TreeMap<String, TreeSet<String>>(); TreeSet<String> registrySet = getClientSet(null); if (registrySet != null) { for (String dnsbl : registrySet) { int index = dnsbl.indexOf(';'); String server = dnsbl.substring(0, index); String value = dnsbl.substring(index + 1); TreeSet<String> dnsblSet = dnsblMap.get(server); if (dnsblSet == null) { dnsblSet = new TreeSet<String>(); dnsblMap.put(server, dnsblSet); } dnsblSet.add(value); } } if (client != null) { registrySet = getClientSet(client); if (registrySet != null) { for (String dnsbl : registrySet) { int index = dnsbl.indexOf(';'); String server = dnsbl.substring(0, index); String value = dnsbl.substring(index + 1); TreeSet<String> dnsblSet = dnsblMap.get(server); if (dnsblSet == null) { dnsblSet = new TreeSet<String>(); dnsblMap.put(server, dnsblSet); } dnsblSet.add(value); } } } for (String server : dnsblMap.keySet()) { TreeSet<String> valueSet = dnsblMap.get(server); String listed = Reverse.getListedIP(ip, server, valueSet); if (listed != null) { Server.logDebug("IP " + ip + " is listed in '" + server + ";" + listed + "'."); if (client == null) { return "DNSBL=" + server + ";" + listed; } else if ((registrySet = getClientSet(null)) == null) { return client + ":DNSBL=" + server + ";" + listed; } else if (registrySet.contains(server + ";" + listed)) { return "DNSBL=" + server + ";" + listed; } else { return client + ":DNSBL=" + server + ";" + listed; } } } return null; } } } /** * Conjunto de REGEX para bloqueio. */ private static class REGEX { private static final HashMap<String, ArrayList<Pattern>> MAP = new HashMap<String, ArrayList<Pattern>>(); public static synchronized boolean isEmpty() { return MAP.isEmpty(); } public static synchronized void clear() { MAP.clear(); } public static synchronized void drop(String client) { MAP.remove(client); } public static TreeSet<String> get(User user) { if (user == null) { return get((String) null); } else { return get(user.getEmail()); } } private static synchronized ArrayList<Pattern> getClientList(String client) { return MAP.get(client); } public static TreeSet<String> get(String user) { TreeSet<String> resultSet = new TreeSet<String>(); ArrayList<Pattern> patternList = getClientList(user); if (patternList != null) { for (Pattern pattern : patternList) { resultSet.add("REGEX=" + pattern.pattern()); } } return resultSet; } private static synchronized ArrayList<String> getKeySet() { ArrayList<String> keySet = new ArrayList<String>(); keySet.addAll(MAP.keySet()); return keySet; } public static int getAll(OutputStream outputStream) throws Exception { int count = 0; for (String client : getKeySet()) { ArrayList<Pattern> patternList = getClientList(client); if (patternList != null) { for (Pattern pattern : patternList) { if (client != null) { outputStream.write(client.getBytes("UTF-8")); outputStream.write(':'); } outputStream.write("REGEX=".getBytes("UTF-8")); outputStream.write(pattern.toString().getBytes("UTF-8")); outputStream.write('\n'); count++; } } } return count; } public static TreeSet<String> getAll() { TreeSet<String> set = new TreeSet<String>(); for (String client : getKeySet()) { ArrayList<Pattern> patternList = getClientList(client); if (patternList != null) { for (Pattern pattern : patternList) { if (client == null) { set.add("REGEX=" + pattern); } else { set.add(client + ":REGEX=" + pattern); } } } } return set; } private static boolean dropExact(String token) { if (token == null) { return false; } else { int index = token.indexOf('='); String regex = token.substring(index + 1); index = token.indexOf(':'); String client; if (index == -1) { client = null; } else if (Domain.isEmail(token.substring(0, index))) { client = token.substring(0, index); } else { client = null; } ArrayList<Pattern> list = getClientList(client); if (list == null) { return false; } else { for (index = 0; index < list.size(); index++) { Pattern pattern = list.get(index); if (regex.equals(pattern.pattern())) { list.remove(index); if (list.isEmpty()) { drop(client); } return true; } } return false; } } } private static synchronized boolean addExact(String client, String token) { int index = token.indexOf('='); String regex = token.substring(index + 1); ArrayList<Pattern> list = MAP.get(client); if (list == null) { list = new ArrayList<Pattern>(); MAP.put(client, list); } Pattern pattern = Pattern.compile(regex); return list.add(pattern); } private static synchronized boolean addExact(String token) { int index = token.indexOf('='); String regex = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } ArrayList<Pattern> list = MAP.get(client); if (list == null) { list = new ArrayList<Pattern>(); MAP.put(client, list); } for (index = 0; index < list.size(); index++) { Pattern pattern = list.get(index); if (regex.equals(pattern.pattern())) { return false; } } Pattern pattern = Pattern.compile(regex); list.add(pattern); return true; } public static boolean contains(String client, String regex) { if (regex == null) { return false; } else { ArrayList<Pattern> patternList = getClientList(client); if (patternList == null) { return false; } else { for (Pattern pattern : patternList) { if (regex.equals(pattern.pattern())) { return true; } } } return false; } } public static String find(String token) { if (token == null) { return null; } else { ArrayList<Pattern> patternList = getClientList(null); if (patternList == null) { return null; } else { for (Pattern pattern : patternList) { Matcher matcher = pattern.matcher(token); if (matcher.matches()) { return "REGEX=" + pattern.pattern(); } } } return null; } } private static String get(String client, Collection<String> tokenList, boolean autoBlock) throws ProcessException { if (tokenList.isEmpty()) { return null; } else { String result = null; ArrayList<Pattern> patternList = getClientList(null); if (patternList != null) { for (Object object : patternList.toArray()) { Pattern pattern = (Pattern) object; for (String token : tokenList) { if (token.contains("@") == pattern.pattern().contains("@")) { Matcher matcher = pattern.matcher(token); if (matcher.matches()) { String regex = "REGEX=" + pattern.pattern(); if (autoBlock && Block.addExact(token)) { Server.logDebug("new BLOCK '" + token + "' added by '" + regex + "'."); if (client == null) { Peer.sendBlockToAll(token); } } result = regex; break; } } } } } if (result == null && client != null) { patternList = getClientList(client); if (patternList != null) { for (Object object : patternList.toArray()) { Pattern pattern = (Pattern) object; for (String token : tokenList) { if (token.contains("@") == pattern.pattern().contains("@")) { Matcher matcher = pattern.matcher(token); if (matcher.matches()) { String regex = "REGEX=" + pattern.pattern(); token = client + ":" + token; if (autoBlock && addExact(token)) { Server.logDebug("new BLOCK '" + token + "' added by '" + client + ":" + regex + "'."); } result = client + ":" + regex; break; } } } } } } return result; } } } /** * Representa o conjunto de blocos IP bloqueados. */ private static class CIDR { private static final HashMap<String, TreeSet<String>> MAP = new HashMap<String, TreeSet<String>>(); public static synchronized boolean isEmpty() { return MAP.isEmpty(); } public static synchronized void clear() { MAP.clear(); } public static synchronized ArrayList<String> getKeySet() { ArrayList<String> resultSet = new ArrayList<String>(); resultSet.addAll(MAP.keySet()); return resultSet; } public static synchronized TreeSet<String> getClientSet(String client) { return MAP.get(client); } public static synchronized TreeSet<String> cloneClientSet(String client) { TreeSet<String> clientSet = MAP.get(client); if (clientSet == null) { return null; } else { TreeSet<String> resultSet = new TreeSet<String>(); resultSet.addAll(clientSet); return resultSet; } } public static synchronized Object[] getClientArray(String client) { TreeSet<String> clientSet = MAP.get(client); if (clientSet == null) { return null; } else { return clientSet.toArray(); } } public static synchronized TreeSet<String> getExtended() { TreeSet<String> returnSet = new TreeSet<String>(); TreeSet<String> cidrSet = MAP.get(null); if (cidrSet != null) { returnSet.addAll(cidrSet); } return returnSet; } public static TreeSet<String> get(User user) { if (user == null) { return get((String) null); } else { return get(user.getEmail()); } } public static TreeSet<String> get(String user) { TreeSet<String> resultSet = new TreeSet<String>(); TreeSet<String> cidrSet = cloneClientSet(user); if (cidrSet != null) { for (String cidr : cidrSet) { if (cidr.contains(":")) { cidr = SubnetIPv6.normalizeCIDRv6(cidr); } else { cidr = SubnetIPv4.normalizeCIDRv4(cidr); } resultSet.add("CIDR=" + cidr); } } return resultSet; } public static int getAll(OutputStream outputStream) throws Exception { int count = 0; for (String client : getKeySet()) { Object[] clientSet = getClientArray(client); if (clientSet != null) { for (Object cidrObj : clientSet) { String cidr = (String) cidrObj; if (cidr.contains(":")) { cidr = SubnetIPv6.normalizeCIDRv6(cidr); } else { cidr = SubnetIPv4.normalizeCIDRv4(cidr); } if (client != null) { outputStream.write(client.getBytes("UTF-8")); outputStream.write(':'); } outputStream.write("CIDR=".getBytes("UTF-8")); outputStream.write(cidr.getBytes("UTF-8")); outputStream.write('\n'); count++; } } } return count; } public static TreeSet<String> getAll() { TreeSet<String> set = new TreeSet<String>(); for (String client : getKeySet()) { Object[] clientArray = getClientArray(client); if (clientArray != null) { for (Object element : clientArray) { String cidr = (String) element; if (cidr.contains(":")) { cidr = SubnetIPv6.normalizeCIDRv6(cidr); } else { cidr = SubnetIPv4.normalizeCIDRv4(cidr); } if (client == null) { set.add("CIDR=" + cidr); } else { set.add(client + ":CIDR=" + cidr); } } } } return set; } private static boolean split(String cidr) { if (dropExact(cidr)) { cidr = cidr.substring(5); short mask = Subnet.getMask(cidr); String first = Subnet.getFirstIP(cidr); String last = Subnet.getLastIP(cidr); int max = SubnetIPv4.isValidIPv4(first) ? 32 : 128; if (mask < max) { mask++; String cidr1 = first + "/" + mask; String cidr2 = last + "/" + mask; cidr1 = "CIDR=" + Subnet.normalizeCIDR(cidr1); cidr2 = "CIDR=" + Subnet.normalizeCIDR(cidr2); boolean splited = true; if (!addExact(null, cidr1)) { splited = false; } if (!addExact(null, cidr2)) { splited = false; } return splited; } else { return false; } } else { return false; } } private static synchronized boolean dropExact(String token) { if (token == null) { return false; } else { int index = token.indexOf('='); String cidr = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } TreeSet<String> set = MAP.get(client); if (set == null) { return false; } else { String key = Subnet.expandCIDR(cidr); boolean removed = set.remove(key); if (set.isEmpty()) { MAP.remove(client); } return removed; } } } public static void simplify() { try { TreeSet<String> cidrSet = getClientSet(null); if (cidrSet != null && !cidrSet.isEmpty()) { String cidrExtended = cidrSet.first(); do { if (SubnetIPv4.isValidCIDRv4(cidrExtended)) { String cidrSmaller = SubnetIPv4.normalizeCIDRv4(cidrExtended); short mask = Subnet.getMask(cidrSmaller); if (mask > 8) { String ipFirst = SubnetIPv4.getFirstIPv4(cidrSmaller); String cidrBigger = SubnetIPv4.normalizeCIDRv4(ipFirst + "/" + (mask - 1)); ipFirst = SubnetIPv4.getFirstIPv4(cidrBigger); String ipLast = SubnetIPv4.getLastIPv4(cidrBigger); String cidr1 = SubnetIPv4.normalizeCIDRv4(ipFirst + "/" + mask); if (CIDR.contains((String) null, cidr1)) { String cidr2 = SubnetIPv4.normalizeCIDRv4(ipLast + "/" + mask); if (CIDR.contains((String) null, cidr2)) { CIDR.dropExact(SubnetIPv4.expandCIDRv4(cidr1)); CIDR.dropExact(SubnetIPv4.expandCIDRv4(cidr2)); CIDR.addExact(null, cidrBigger); } } } } else if (SubnetIPv6.isValidCIDRv6(cidrExtended)) { String cidrSmaller = SubnetIPv6.normalizeCIDRv6(cidrExtended); short mask = Subnet.getMask(cidrSmaller); if (mask > 16) { String ipFirst = SubnetIPv6.getFirstIPv6(cidrSmaller); String cidrBigger = SubnetIPv6.normalizeCIDRv6(ipFirst + "/" + (mask - 1)); ipFirst = SubnetIPv6.getFirstIPv6(cidrBigger); String ipLast = SubnetIPv6.getLastIPv6(cidrBigger); String cidr1 = SubnetIPv6.normalizeCIDRv6(ipFirst + "/" + mask); if (CIDR.contains((String) null, cidr1)) { String cidr2 = SubnetIPv6.normalizeCIDRv6(ipLast + "/" + mask); if (CIDR.contains((String) null, cidr2)) { CIDR.dropExact(SubnetIPv6.expandCIDRv6(cidr1)); CIDR.dropExact(SubnetIPv6.expandCIDRv6(cidr2)); CIDR.addExact(null, cidrBigger); } } } } } while ((cidrExtended = cidrSet.higher(cidrExtended)) != null); } } catch (Exception ex) { Server.logError(ex); } } private static synchronized boolean addExact(String client, String token) { int index = token.indexOf('='); String cidr = token.substring(index + 1); TreeSet<String> set = MAP.get(client); if (set == null) { set = new TreeSet<String>(); MAP.put(client, set); } String key = Subnet.expandCIDR(cidr); return set.add(key); } private static synchronized boolean addExact(String token, boolean overlap) throws ProcessException { int index = token.indexOf('='); String cidr = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } TreeSet<String> set = MAP.get(client); if (set == null) { set = new TreeSet<String>(); MAP.put(client, set); } String key = Subnet.expandCIDR(cidr); if (set.contains(key)) { return false; } else { String firstCIDR = Subnet.getFirstIP(cidr); String lastCIDR = Subnet.getLastIP(cidr); String firstExpanded = Subnet.expandIP(firstCIDR) + "/00"; String lastExpanded = Subnet.expandIP(lastCIDR) + "/99"; String floorExpanded = set.floor(firstExpanded); String floor = Subnet.normalizeCIDR(floorExpanded); TreeSet<String> intersectsSet = new TreeSet<String>(); intersectsSet.addAll(set.subSet(firstExpanded, lastExpanded)); if (Subnet.containsIP(floor, firstCIDR)) { intersectsSet.add(floorExpanded); } TreeSet<String> overlapSet = new TreeSet<String>(); StringBuilder errorBuilder = new StringBuilder(); for (String elementExpanded : intersectsSet) { String element = Subnet.normalizeCIDR(elementExpanded); String elementFirst = Subnet.getFirstIP(element); String elementLast = Subnet.getLastIP(element); if (!Subnet.containsIP(cidr, elementFirst)) { errorBuilder.append("INTERSECTS "); errorBuilder.append(element); errorBuilder.append('\n'); } else if (!Subnet.containsIP(cidr, elementLast)) { errorBuilder.append("INTERSECTS "); errorBuilder.append(element); errorBuilder.append('\n'); } else if (overlap) { overlapSet.add(elementExpanded); } else { errorBuilder.append("CONTAINS "); errorBuilder.append(element); errorBuilder.append('\n'); } } String error = errorBuilder.toString(); if (error.length() == 0) { set.removeAll(overlapSet); if (set.add(key)) { try { // Join algorithm. short mask; while ((mask = Subnet.getMask(cidr)) > 8) { String ipFirst = Subnet.getFirstIP(cidr); cidr = Subnet.normalizeCIDR(ipFirst + "/" + (mask - 1)); ipFirst = Subnet.getFirstIP(cidr); String ipLast = Subnet.getLastIP(cidr); String cidr1 = Subnet.normalizeCIDR(ipFirst + "/" + mask); String cidrExpanded1 = Subnet.expandCIDR(cidr1); if (set.contains(cidrExpanded1)) { String cidr2 = Subnet.normalizeCIDR(ipLast + "/" + mask); String cidrExpanded2 = Subnet.expandCIDR(cidr2); if (set.contains(cidrExpanded2)) { String cidrBiggerExpanded = Subnet.expandCIDR(cidr); set.remove(cidrExpanded1); set.remove(cidrExpanded2); set.add(cidrBiggerExpanded); } else { break; } } else { break; } } } catch (Exception ex) { Server.logError(ex); } return true; } else { return false; } } else { throw new ProcessException(error); } } } public static boolean contains(Client client, String cidr) { if (client == null) { return contains((String) null, cidr); } else { return contains(client.getEmail(), cidr); } } public static boolean contains(String client, String cidr) { if (cidr == null) { return false; } else { String key = Subnet.expandCIDR(cidr); TreeSet<String> cidrSet = getClientSet(client); if (cidrSet == null) { return false; } else { return cidrSet.contains(key); } } } private static String getFloor(String client, String ip) { TreeSet<String> cidrSet = getClientSet(client); if (cidrSet == null || cidrSet.isEmpty()) { return null; } else if (SubnetIPv4.isValidIPv4(ip)) { String key = SubnetIPv4.expandIPv4(ip); String cidr = cidrSet.floor(key + "/9"); if (cidr == null) { return null; } else if (cidr.contains(".")) { return SubnetIPv4.normalizeCIDRv4(cidr); } else { return null; } } else if (SubnetIPv6.isValidIPv6(ip)) { String key = SubnetIPv6.expandIPv6(ip); String cidr = cidrSet.floor(key + "/9"); if (cidr == null) { return null; } else if (cidr.contains(":")) { return SubnetIPv6.normalizeCIDRv6(cidr); } else { return null; } } else { return null; } } public static String get(String client, String ip) { // long time = System.currentTimeMillis(); String result; String cidr = getFloor(null, ip); if (Subnet.containsIP(cidr, ip)) { result = "CIDR=" + cidr; } else if (client == null) { result = null; } else if ((cidr = getFloor(client, ip)) == null) { result = null; } else if (Subnet.containsIP(cidr, ip)) { result = client + ":CIDR=" + cidr; } else { result = null; } // logTrace(time, "CIDR lookup for '" + ip + "'."); return result; } } public static void dropExpired() { long max = System.currentTimeMillis() - Server.DAY_TIME * 40L; TreeMap<String, Long> map = SET.getMap(); for (String token : map.keySet()) { Long time = map.get(token); if (time == null || time < max) { if (SET.dropExact(token)) { Server.logDebug("expired BLOCK '" + token + "'."); } } } } public static boolean dropExact(String token) { if (token == null) { return false; } else if (token.contains("DNSBL=")) { if (DNSBL.dropExact(token)) { return CHANGED = true; } else { return false; } } else if (token.contains("CIDR=")) { if (CIDR.dropExact(token)) { return CHANGED = true; } else { return false; } } else if (token.contains("REGEX=")) { if (REGEX.dropExact(token)) { return CHANGED = true; } else { return false; } } else if (token.contains("WHOIS/")) { if (WHOIS.dropExact(token)) { return CHANGED = true; } else { return false; } } else if (SET.dropExact(token)) { return CHANGED = true; } else { return false; } } public static boolean dropAll() { SET.clear(); CIDR.clear(); REGEX.clear(); DNSBL.clear(); WHOIS.clear(); CHANGED = true; return true; } public static boolean addExact(String token) throws ProcessException { if (token == null) { return false; } else if (token.contains("WHOIS/")) { if (WHOIS.addExact(token)) { CHANGED = true; return true; } else { return false; } } else if (token.contains("DNSBL=")) { if (DNSBL.addExact(token)) { CHANGED = true; return true; } else { return false; } } else if (token.contains("CIDR=")) { if (CIDR.addExact(token, false)) { CHANGED = true; return true; } else { return false; } } else if (token.contains("REGEX=")) { if (REGEX.addExact(token)) { CHANGED = true; return true; } else { return false; } } else if (SET.addExact(token)) { CHANGED = true; return true; } else { return false; } } public static TreeSet<String> getExtendedCIDR() { return CIDR.getExtended(); } public static TreeSet<String> getAll() throws ProcessException { TreeSet<String> blockSet = SET.getAll(); blockSet.addAll(CIDR.getAll()); blockSet.addAll(REGEX.getAll()); blockSet.addAll(DNSBL.getAll()); blockSet.addAll(WHOIS.getAll()); return blockSet; } public static TreeSet<String> get(String user) throws ProcessException { TreeSet<String> blockSet = SET.get(user); blockSet.addAll(CIDR.get(user)); blockSet.addAll(REGEX.get(user)); blockSet.addAll(DNSBL.get(user)); blockSet.addAll(WHOIS.get(user)); return blockSet; } public static boolean containsExact(User user, String token) { if (user == null || token == null) { return false; } else { return SET.contains(user.getEmail() + ":" + token); } } public static boolean containsExact(String user, String token) { if (token == null) { return false; } else if (user == null) { return SET.contains(token); } else { return SET.contains(user + ":" + token); } } public static boolean containsExact(String token) { if (token.contains("WHOIS/")) { int index = token.indexOf('/'); String whois = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } return WHOIS.contains(client, whois); } else if (token.contains("DNSBL=")) { int index = token.indexOf('='); String dnsbl = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } return DNSBL.contains(client, dnsbl); } else if (token.contains("CIDR=")) { int index = token.indexOf('='); String cidr = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } return CIDR.contains(client, cidr); } else if (token.contains("REGEX=")) { int index = token.indexOf('='); String regex = token.substring(index + 1); index = token.lastIndexOf(':', index); String client; if (index == -1) { client = null; } else { client = token.substring(0, index); } return REGEX.contains(client, regex); } else { return SET.contains(token); } } private static String addDomain(String user, String token) { try { if (token == null) { return null; } else if (token.startsWith("@") && (token = Domain.extractDomain(token.substring(1), true)) != null) { if (user == null && addExact(token)) { return token; } else if (user != null && addExact(user + ':' + token)) { return user + ':' + token; } else { return null; } } else if (token.startsWith(".") && (token = Domain.extractDomain(token, true)) != null) { if (user == null && addExact(token)) { return token; } else if (user != null && addExact(user + ':' + token)) { return user + ':' + token; } else { return null; } } else { return null; } } catch (ProcessException ex) { return null; } } private static String normalizeTokenBlock(String token) throws ProcessException { int index = token.indexOf(':'); if (index > 0 && Domain.isEmail(token.substring(0, index))) { String client = token.substring(0, index).toLowerCase(); token = token.substring(index + 1); token = SPF.normalizeToken(token, true, true, true, true, true, true); if (token == null) { return null; } else { return client + ":" + token; } } else { return SPF.normalizeToken(token, true, true, true, true, true, true); } } public static boolean tryAdd(String token) { try { return add(token) != null; } catch (ProcessException ex) { return false; } } public static String addSafe(String token) { try { if ((token = normalizeTokenBlock(token)) == null) { return null; } else if (addExact(token)) { return token; } else { return null; } } catch (ProcessException ex) { return null; } } public static String add(String token) throws ProcessException { if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else if (addExact(token)) { return token; } else { return null; } } public static boolean tryOverlap(String cidr) { try { return overlap(cidr); } catch (ProcessException ex) { return false; } } public static boolean overlap(String cidr) throws ProcessException { if ((cidr = normalizeTokenBlock(cidr)) == null) { throw new ProcessException("TOKEN INVALID"); } else if (!cidr.startsWith("CIDR=")) { throw new ProcessException("TOKEN INVALID"); } else { return CIDR.addExact(cidr, true); } } public static boolean add(String client, String token) throws ProcessException { if (client == null || !Domain.isEmail(client)) { throw new ProcessException("CLIENT INVALID"); } else if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else { return addExact(client + ':' + token); } } public static boolean addSafe(User user, String token) { try { return add(user, token); } catch (ProcessException ex) { return false; } } public static boolean add(User user, String token) throws ProcessException { if (user == null) { throw new ProcessException("USER INVALID"); } else if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else { return addExact(user.getEmail() + ":" + token); } } public static String addIfNotNull(User user, String token) throws ProcessException { if (user == null) { return null; } else if ((token = normalizeTokenBlock(token)) == null) { return null; } else if (addExact(user.getEmail() + ":" + token)) { return user.getEmail() + ":" + token; } else { return null; } } public static boolean add(Client client, String token) throws ProcessException { if (client == null || !client.hasEmail()) { throw new ProcessException("CLIENT INVALID"); } else if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else { return addExact(client.getEmail() + ':' + token); } } public static boolean drop(String token) throws ProcessException { if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else if (dropExact(token)) { return true; } else { return false; } } public static boolean drop(String client, String token) throws ProcessException { if (client == null || !Domain.isEmail(client)) { throw new ProcessException("CLIENT INVALID"); } else if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else { return dropExact(client + ':' + token); } } public static boolean drop(User user, String token) throws ProcessException { if (user == null) { throw new ProcessException("USER INVALID"); } else if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else { return dropExact(user.getEmail() + ':' + token); } } public static boolean drop(Client client, String token) throws ProcessException { if (client == null || !client.hasEmail()) { throw new ProcessException("CLIENT INVALID"); } else if ((token = normalizeTokenBlock(token)) == null) { throw new ProcessException("TOKEN INVALID"); } else { return dropExact(client.getEmail() + ':' + token); } } public static TreeSet<String> get(Client client, User user) throws ProcessException { TreeSet<String> blockSet = new TreeSet<String>(); // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } else if (client != null) { userEmail = client.getEmail(); } if (userEmail != null) { for (String token : get(userEmail)) { int index = token.indexOf(':') + 1; token = token.substring(index); blockSet.add(token); } } return blockSet; } public static TreeSet<String> getSet(User user) throws ProcessException { return SET.get(user); } public static TreeSet<String> getAll(Client client, User user) throws ProcessException { TreeSet<String> blockSet = new TreeSet<String>(); // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } else if (client != null) { userEmail = client.getEmail(); } for (String token : getAll()) { if (!token.contains(":")) { blockSet.add(token); } else if (userEmail != null && token.startsWith(userEmail + ':')) { int index = token.indexOf(':') + 1; token = token.substring(index); blockSet.add(token); } } return blockSet; } public static TreeSet<String> getAllTokens(String value) { TreeSet<String> blockSet = new TreeSet<String>(); if (Subnet.isValidIP(value)) { String ip = Subnet.normalizeIP(value); if (SET.contains(ip)) { blockSet.add(ip); } } else if (Subnet.isValidCIDR(value)) { String cidr = Subnet.normalizeCIDR(value); if (CIDR.contains((String) null, cidr)) { blockSet.add(cidr); } TreeSet<String> set = SET.getAll(); for (String ip : set) { if (Subnet.containsIP(cidr, ip)) { blockSet.add(ip); } } for (String ip : set) { if (SubnetIPv6.containsIP(cidr, ip)) { blockSet.add(ip); } } } else if (Domain.isHostname(value)) { LinkedList<String> regexList = new LinkedList<String>(); String host = Domain.normalizeHostname(value, true); do { int index = host.indexOf('.') + 1; host = host.substring(index); if (Block.dropExact('.' + host)) { blockSet.add('.' + host); regexList.addFirst('.' + host); } } while (host.contains(".")); } else if (SET.contains(value)) { blockSet.add(value); } return blockSet; } public static int getAll(OutputStream outputStream) throws Exception { int count = SET.getAll(outputStream); count += CIDR.getAll(outputStream); count += REGEX.getAll(outputStream); count += DNSBL.getAll(outputStream); count += WHOIS.getAll(outputStream); outputStream.flush(); return count; } public static int get(OutputStream outputStream) throws IOException { int count = 0; TreeSet<String> set; if ((set = SET.get((User) null)) != null) { for (String token : set) { outputStream.write(token.getBytes("UTF-8")); outputStream.write('\n'); outputStream.flush(); count++; } } if ((set = CIDR.get((User) null)) != null) { for (String token : set) { outputStream.write(token.getBytes("UTF-8")); outputStream.write('\n'); outputStream.flush(); count++; } } if ((set = REGEX.get((User) null)) != null) { for (String token : set) { outputStream.write(token.getBytes("UTF-8")); outputStream.write('\n'); outputStream.flush(); count++; } } if ((set = DNSBL.get((User) null)) != null) { for (String token : set) { outputStream.write(token.getBytes("UTF-8")); outputStream.write('\n'); outputStream.flush(); count++; } } if ((set = WHOIS.get((User) null)) != null) { for (String token : set) { outputStream.write(token.getBytes("UTF-8")); outputStream.write('\n'); outputStream.flush(); count++; } } return count; } public static TreeSet<String> get() throws ProcessException { TreeSet<String> blockSet = new TreeSet<String>(); for (String token : getAll()) { if (!token.contains(":")) { blockSet.add(token); } } return blockSet; } public static void clear(String token, String name) { try { if (SubnetIPv4.isValidIPv4(token)) { String ip = SubnetIPv4.normalizeIPv4(token); if (Block.clearCIDR(ip, 32) != null) { Server.logInfo("false positive BLOCK '" + ip + "/32' detected by '" + name + "'."); } } else if (SubnetIPv6.isValidIPv6(token)) { String ip = SubnetIPv6.normalizeIPv6(token); if (Block.clearCIDR(ip, 64) != null) { Server.logInfo("false positive BLOCK '" + ip + "/64' detected by '" + name + "'."); } } TreeSet<String> blockSet = new TreeSet<String>(); String block; while ((block = Block.find(null, null, token, false, true, true, false)) != null) { if (blockSet.contains(block)) { throw new ProcessException("FATAL BLOCK ERROR " + block); } else if (Block.drop(block)) { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + name + "'."); } blockSet.add(block); } } catch (ProcessException ex) { Server.logError(ex); } } public static void clear(User user, String token, String name) { try { String block; if (SubnetIPv4.isValidIPv4(token)) { String ip = SubnetIPv4.normalizeIPv4(token); if ((block = Block.clearCIDR(ip, 32)) != null) { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + name + "'."); } } else if (SubnetIPv6.isValidIPv6(token)) { String ip = SubnetIPv6.normalizeIPv6(token); if ((block = Block.clearCIDR(ip, 64)) != null) { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + name + "'."); } } TreeSet<String> blockSet = new TreeSet<String>(); while ((block = Block.find(null, user, token, false, true, true, false)) != null) { if (blockSet.contains(block)) { throw new ProcessException("FATAL BLOCK ERROR " + block); } else if (Block.drop(block)) { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + name + "'."); } blockSet.add(block); } } catch (ProcessException ex) { Server.logError(ex); } } public static void clearHREF(User user, String token, String name) { try { TreeSet<String> blockSet = new TreeSet<String>(); String block; while ((block = Block.findHREF(null, user, token, false)) != null) { if (blockSet.contains(block)) { throw new ProcessException("FATAL BLOCK ERROR " + block); } else if (Block.drop(block)) { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + name + "'."); } blockSet.add(block); } } catch (ProcessException ex) { Server.logError(ex); } } public static String clearCIDR(String ip, int mask) { try { if (Subnet.isValidIP(ip)) { TreeSet<String> blockSet = new TreeSet<String>(); String cidr; while ((cidr = CIDR.get(null, ip)) != null) { if (blockSet.contains(cidr)) { throw new ProcessException("FATAL BLOCK ERROR " + cidr); } else if (!CIDR.split(cidr)) { return cidr; } blockSet.add(cidr); } return null; } else { return null; } } catch (ProcessException ex) { Server.logError(ex); return null; } } public static boolean clearCIDR(String ip, String admin) { if (ip == null) { return false; } else { String cidr; int mask = SubnetIPv4.isValidIPv4(ip) ? 32 : 64; if ((cidr = Block.clearCIDR(ip, mask)) != null) { Server.logInfo("false positive BLOCK '" + cidr + "' detected by '" + admin + "'."); return true; } else { return false; } } } public static String find(User user, String token, boolean findDNSBL, boolean findREGEX, boolean findWHOIS) { // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } return find(userEmail, token, findDNSBL, findREGEX, findWHOIS, false); } public static String findHREF(User user, String token) { // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } return findHREF(userEmail, token, false); } public static String find(User user, String token, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoBlock) { // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } return find(userEmail, token, findDNSBL, findREGEX, findWHOIS, autoBlock); } public static String find(Client client, User user, String token, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoBlock) { // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } else if (client != null) { userEmail = client.getEmail(); } return find(userEmail, token, findDNSBL, findREGEX, findWHOIS, autoBlock); } public static String findHREF(Client client, User user, String token, boolean autoBlock) { // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } else if (client != null) { userEmail = client.getEmail(); } return findHREF(userEmail, token, autoBlock); } public static String find(String userEmail, String token, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoBlock) { TreeSet<String> whoisSet = new TreeSet<String>(); LinkedList<String> regexList = new LinkedList<String>(); if (token == null) { return null; } else if (Domain.isEmail(token)) { String sender = token.toLowerCase(); int index1 = sender.indexOf('@'); int index2 = sender.lastIndexOf('@'); String part = sender.substring(0, index1 + 1); String senderDomain = sender.substring(index2); if (SET.contains(sender)) { return sender; } else if (userEmail != null && SET.contains(userEmail + ':' + sender)) { return userEmail + ':' + sender; } else if (SET.contains(part)) { return part; } else if (userEmail != null && SET.contains(userEmail + ':' + part)) { return userEmail + ':' + part; } else if (SET.contains(senderDomain)) { return senderDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain)) { return userEmail + ':' + senderDomain; } else { int index3 = senderDomain.length(); while ((index3 = senderDomain.lastIndexOf('.', index3 - 1)) > index2) { String subdomain = senderDomain.substring(0, index3 + 1); if (SET.contains(subdomain)) { return subdomain; } else if (userEmail != null && SET.contains(userEmail + ':' + subdomain)) { return userEmail + ':' + subdomain; } } String host = '.' + senderDomain.substring(1); do { int index = host.indexOf('.') + 1; host = host.substring(index); String token2 = '.' + host; if (SET.contains(token2)) { return token2; } else if (userEmail != null && SET.contains(userEmail + ':' + token2)) { return userEmail + ':' + token2; } regexList.addFirst(token2); } while (host.contains(".")); int index4 = sender.length(); while ((index4 = sender.lastIndexOf('.', index4 - 1)) > index2) { String subsender = sender.substring(0, index4 + 1); if (SET.contains(subsender)) { return subsender; } else if (userEmail != null && SET.contains(userEmail + ':' + subsender)) { return userEmail + ':' + subsender; } } } if (senderDomain.endsWith(".br")) { whoisSet.add(senderDomain); } regexList.add(sender); } else if (Subnet.isValidIP(token)) { token = Subnet.normalizeIP(token); String cidr; String dnsbl; if (SET.contains(token)) { return token; } else if (userEmail != null && SET.contains(userEmail + ':' + token)) { return userEmail + ':' + token; } else if ((cidr = CIDR.get(userEmail, token)) != null) { return cidr; } else if (findDNSBL && (dnsbl = DNSBL.get(userEmail, token)) != null) { return dnsbl; } Reverse reverse = Reverse.get(token); if (reverse != null) { for (String host : reverse.getAddressSet()) { String block = find(userEmail, host, findDNSBL, findREGEX, findWHOIS, autoBlock); if (block != null) { return block; } } } regexList.add(token); } else if (Domain.isHostname(token)) { token = Domain.normalizeHostname(token, true); String host = token; do { int index = host.indexOf('.') + 1; host = host.substring(index); String token2 = '.' + host; if (SET.contains(token2)) { return token2; } else if (userEmail != null && SET.contains(userEmail + ':' + token2)) { return userEmail + ':' + token2; } regexList.addFirst(token2); } while (host.contains(".")); if (token.endsWith(".br")) { whoisSet.add(token); } } else { regexList.add(token); } if (findREGEX) { try { // Verifica um critrio do REGEX. String regex; if ((regex = REGEX.get(userEmail, regexList, autoBlock)) != null) { return regex; } } catch (Exception ex) { Server.logError(ex); } } if (findWHOIS) { try { // Verifica critrios do WHOIS. String whois; if ((whois = WHOIS.get(userEmail, whoisSet, autoBlock)) != null) { return whois; } } catch (Exception ex) { Server.logError(ex); } } return null; } public static String findHREF(String userEmail, String token, boolean autoBlock) { if (token == null) { return null; } else if (Domain.isEmail(token)) { String sender = token.toLowerCase(); int index1 = sender.indexOf('@'); int index2 = sender.lastIndexOf('@'); String part = sender.substring(0, index1 + 1); String senderDomain = sender.substring(index2); if (SET.contains("HREF=" + sender)) { return "HREF=" + sender; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + sender)) { return userEmail + ":HREF=" + sender; } else if (SET.contains("HREF=" + part)) { return "HREF=" + part; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + part)) { return userEmail + ":HREF=" + part; } else if (SET.contains("HREF=" + senderDomain)) { return "HREF=" + senderDomain; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + senderDomain)) { return userEmail + ":HREF=" + senderDomain; } else { int index3 = senderDomain.length(); while ((index3 = senderDomain.lastIndexOf('.', index3 - 1)) > index2) { String subdomain = senderDomain.substring(0, index3 + 1); if (SET.contains("HREF=" + subdomain)) { return "HREF=" + subdomain; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + subdomain)) { return userEmail + ":HREF=" + subdomain; } } String host = '.' + senderDomain.substring(1); do { int index = host.indexOf('.') + 1; host = host.substring(index); String token2 = '.' + host; if (SET.contains("HREF=" + token2)) { return "HREF=" + token2; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + token2)) { return userEmail + ":HREF=" + token2; } } while (host.contains(".")); int index4 = sender.length(); while ((index4 = sender.lastIndexOf('.', index4 - 1)) > index2) { String subsender = sender.substring(0, index4 + 1); if (SET.contains("HREF=" + subsender)) { return "HREF=" + subsender; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + subsender)) { return userEmail + ":HREF=" + subsender; } } } String ownerID = Domain.getOwnerID(senderDomain); if (ownerID != null) { if (SET.contains("HREF=" + ownerID)) { return "HREF=" + ownerID; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + ownerID)) { return userEmail + ":HREF=" + ownerID; } } } else if (Subnet.isValidIP(token)) { token = Subnet.normalizeIP(token); if (SET.contains("HREF=" + token)) { return "HREF=" + token; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + token)) { return userEmail + ":HREF=" + token; } Reverse reverse = Reverse.get(token); if (reverse != null) { for (String host : reverse.getAddressSet()) { String block = findHREF(userEmail, host, autoBlock); if (block != null) { return block; } } } } else if (Domain.isHostname(token)) { token = Domain.normalizeHostname(token, true); String host = token; do { int index = host.indexOf('.') + 1; host = host.substring(index); String token2 = '.' + host; if (SET.contains("HREF=" + token2)) { return "HREF=" + token2; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + token2)) { return userEmail + ":HREF=" + token2; } } while (host.contains(".")); String ownerID = Domain.getOwnerID(token); if (ownerID != null) { if (SET.contains("HREF=" + ownerID)) { if (SET.addExact("HREF=" + token)) { Server.logDebug("new BLOCK 'HREF=" + token + "' added by 'HREF=" + ownerID + "'."); } return "HREF=" + ownerID; } else if (userEmail != null && SET.contains(userEmail + ":HREF=" + ownerID)) { if (SET.addExact(userEmail + ":HREF=" + token)) { Server.logDebug("new BLOCK '" + userEmail + ":HREF=" + token + "' added by '" + userEmail + ":HREF=" + token + "'."); } return userEmail + ":HREF=" + ownerID; } } } return null; } public static void clear(Client client, User user, String ip, String sender, String hostname, String qualifier, String recipient) throws ProcessException { String userEmail = null; if (user != null) { userEmail = user.getEmail(); } else if (client != null) { userEmail = client.getEmail(); } clear(userEmail, ip, sender, hostname, qualifier, recipient); } public static void clear(String userEmail, String ip, String sender, String hostname, String qualifier, String recipient) throws ProcessException { String block; int mask = SubnetIPv4.isValidIPv4(ip) ? 32 : 64; if ((block = Block.clearCIDR(ip, mask)) != null) { if (userEmail == null) { Server.logInfo("false positive BLOCK '" + block + "' detected."); } else { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + userEmail + "'."); } } TreeSet<String> blockSet = new TreeSet<String>(); while ((block = find(userEmail, ip, sender, hostname, qualifier, recipient, false, true, true, false)) != null) { if (blockSet.contains(block)) { throw new ProcessException("FATAL BLOCK ERROR " + block); } else if (dropExact(block)) { if (userEmail == null) { Server.logInfo("false positive BLOCK '" + block + "' detected."); } else { Server.logInfo("false positive BLOCK '" + block + "' detected by '" + userEmail + "'."); } } blockSet.add(block); } } public static boolean contains(String token) { try { if (token.contains("#") || token.contains(".H.")) { String hostname = token.replace("#", "0"); hostname = hostname.replace(".H.", ".0a."); return Block.containsDomain(hostname, false); } else if (Subnet.isValidCIDR(token)) { String cidr = Subnet.normalizeCIDR(token); String firstIP = Subnet.getFirstIP(cidr); String lastIP = Subnet.getLastIP(cidr); String firstCIDR = CIDR.get(null, firstIP); if (firstCIDR == null) { return false; } else { String lastCIDR = CIDR.get(null, lastIP); return firstCIDR.equals(lastCIDR); } } else if (Owner.isOwnerID(token)) { String ownerID = Owner.normalizeID(token); return Block.containsExact("WHOIS/ownerid=" + ownerID); } else if (Domain.isHostname(token)) { String hostname = Domain.normalizeHostname(token, true); return Block.containsDomain(hostname, false); } else { return false; } } catch (ProcessException ex) { Server.logError(ex); return false; } } public static boolean contains(Client client, User user, String ip, String sender, String helo, String qualifier, String recipient, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoblock) throws ProcessException { return find(client, user, ip, sender, helo, qualifier, recipient, findDNSBL, findREGEX, findWHOIS, autoblock) != null; } public static boolean contains(String userEmail, String ip, String sender, String helo, String qualifier, String recipient, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoblock) throws ProcessException { return find(userEmail, ip, sender, helo, qualifier, recipient, findDNSBL, findREGEX, findWHOIS, autoblock) != null; } public static String find(Client client, User user, String ip, String sender, String hostname, String qualifier, String recipient, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoblock) { // Definio do e-mail do usurio. String userEmail = null; if (user != null) { userEmail = user.getEmail(); } else if (client != null) { userEmail = client.getEmail(); } return find(userEmail, ip, sender, hostname, qualifier, recipient, findDNSBL, findREGEX, findWHOIS, autoblock); } public static String find(String userEmail, String ip, String sender, String hostname, String qualifier, String recipient, boolean findDNSBL, boolean findREGEX, boolean findWHOIS, boolean autoblock) { if (sender == null && hostname != null) { sender = "mailer-daemon@" + hostname; } TreeSet<String> whoisSet = new TreeSet<String>(); TreeSet<String> regexSet = new TreeSet<String>(); // Definio do destinatrio. String recipientDomain; if (recipient != null && recipient.contains("@")) { int index = recipient.indexOf('@'); recipient = recipient.toLowerCase(); if (Core.isAbuseEmail(recipient) || (recipient.startsWith("postmaster@") && !recipient.equals(userEmail))) { // No pode haver bloqueio para o postmaster, admin e abuse, // exceto se o bloqueio for especifico destes. String mx = Domain.extractHost(sender, true); String token = (Provider.containsExact(mx) ? sender : mx) + ">" + recipient; if (Block.containsExact(userEmail, token)) { return userEmail == null ? token : userEmail + ":" + token; } else { return null; } } else { recipientDomain = recipient.substring(index); } } else { recipient = null; recipientDomain = null; } String found; if ((found = findSender(userEmail, sender, qualifier, recipient, recipientDomain, whoisSet, regexSet)) != null) { return found; } else if (!qualifier.equals("NONE") && !qualifier.equals("PASS") && (found = findSender(userEmail, sender, "NOTPASS", recipient, recipientDomain, whoisSet, regexSet)) != null) { return found; } else if ((found = findSender(userEmail, sender, ip, recipient, recipientDomain, whoisSet, regexSet)) != null) { return found; } // Verifica o HELO. if ((hostname = Domain.extractHost(hostname, true)) != null) { if ((found = findHost(userEmail, sender, hostname, qualifier, recipient, recipientDomain, whoisSet, regexSet, SPF.matchHELO(ip, hostname))) != null) { return found; } if (hostname.endsWith(".br") && SPF.matchHELO(ip, hostname)) { whoisSet.add(hostname); } regexSet.add(hostname); } // Verifica o IP. if (ip != null) { ip = Subnet.normalizeIP(ip); String cidr; String dnsbl; if (SET.contains(ip)) { return ip; } else if (recipient != null && SET.contains(ip + '>' + recipient)) { return ip + '>' + recipient; } else if (recipientDomain != null && SET.contains(ip + '>' + recipientDomain)) { return ip + '>' + recipientDomain; } else if (SET.contains(ip + ';' + qualifier)) { return ip + ';' + qualifier; } else if (recipient != null && SET.contains(ip + ';' + qualifier + '>' + recipient)) { return ip + ';' + qualifier + '>' + recipient; } else if (recipientDomain != null && SET.contains(ip + ';' + qualifier + '>' + recipientDomain)) { return ip + ';' + qualifier + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ":@;" + ip)) { return userEmail + ":@;" + ip; } else if (userEmail != null && SET.contains(userEmail + ':' + ip)) { return userEmail + ':' + ip; } else if (userEmail != null && recipient != null && SET.contains(userEmail + ':' + ip + '>' + recipient)) { return userEmail + ':' + ip + '>' + recipient; } else if (userEmail != null && recipientDomain != null && SET.contains(userEmail + ':' + ip + '>' + recipientDomain)) { return userEmail + ':' + ip + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + ip + ';' + qualifier)) { return userEmail + ':' + ip + ';' + qualifier; } else if (userEmail != null && recipient != null && SET.contains(userEmail + ':' + ip + ';' + qualifier + '>' + recipient)) { return userEmail + ':' + ip + ';' + qualifier + '>' + recipient; } else if (userEmail != null && recipientDomain != null && SET.contains(userEmail + ':' + ip + ';' + qualifier + '>' + recipientDomain)) { return userEmail + ':' + ip + ';' + qualifier + '>' + recipientDomain; } else if ((cidr = CIDR.get(userEmail, ip)) != null) { return cidr; } else if (findDNSBL && (dnsbl = DNSBL.get(userEmail, ip)) != null) { return dnsbl; } Reverse reverse = Reverse.get(ip); if (reverse != null) { for (String host : reverse.getAddressSet()) { String block = find(userEmail, host, findDNSBL, findREGEX, findWHOIS, autoblock); if (block != null) { return block; } } } regexSet.add(ip); } if (findREGEX) { try { // Verifica um critrio do REGEX. String regex; if ((regex = REGEX.get(userEmail, regexSet, autoblock)) != null) { return regex; } } catch (Exception ex) { Server.logError(ex); } } if (findWHOIS) { try { // Verifica critrios do WHOIS. String whois; if ((whois = WHOIS.get(userEmail, whoisSet, autoblock)) != null) { return whois; } } catch (Exception ex) { Server.logError(ex); } } return null; } public static String findSender(String userEmail, String sender, String validation, String recipient, String recipientDomain, TreeSet<String> whoisSet, TreeSet<String> regexSet) { // Verifica o remetente. if (sender != null && sender.contains("@")) { sender = sender.toLowerCase(); if (sender.startsWith("srs0=") || sender.startsWith("srs0+")) { int index = sender.lastIndexOf('@'); String senderOriginal = sender.substring(0, index); if (senderOriginal.startsWith("srs0+")) { senderOriginal = senderOriginal.replaceFirst("^srs0\\+", "srs0="); } StringTokenizer tokenizer = new StringTokenizer(senderOriginal, "="); if (tokenizer.countTokens() == 5) { tokenizer.nextToken(); tokenizer.nextToken(); tokenizer.nextToken(); String senderDomain = tokenizer.nextToken(); String part = tokenizer.nextToken(); senderOriginal = part + '@' + senderDomain; String block = Block.find(userEmail, senderOriginal, false, true, true, false); if (block != null) { return block; } } } int index1 = sender.indexOf('@'); int index2 = sender.lastIndexOf('@'); String part = sender.substring(0, index1 + 1); String senderDomain = sender.substring(index2); String host; if (SET.contains(sender)) { return sender; } else if (SET.contains(sender + ';' + validation + '>' + recipient)) { return sender + ';' + validation + '>' + recipient; } else if (SET.contains(sender + ';' + validation + '>' + recipientDomain)) { return sender + ';' + validation + '>' + recipientDomain; } else if (SET.contains(sender + ';' + validation)) { return sender + ';' + validation; } else if (SET.contains(sender + ';' + validation + '>' + recipient)) { return sender + ';' + validation + '>' + recipient; } else if (SET.contains(sender + ';' + validation + '>' + recipientDomain)) { return sender + ';' + validation + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + sender)) { return userEmail + ':' + sender; } else if (userEmail != null && SET.contains(userEmail + ':' + sender + '>' + recipient)) { return userEmail + ':' + sender + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + sender + '>' + recipientDomain)) { return userEmail + ':' + sender + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + sender + ';' + validation)) { return userEmail + ':' + sender + ';' + validation; } else if (userEmail != null && SET.contains(userEmail + ':' + sender + ';' + validation + '>' + recipient)) { return userEmail + ':' + sender + ';' + validation + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + sender + ';' + validation + '>' + recipientDomain)) { return userEmail + ':' + sender + ';' + validation + '>' + recipientDomain; } else if (SET.contains(part)) { return part; } else if (SET.contains(part + '>' + recipient)) { return part + '>' + recipient; } else if (SET.contains(part + '>' + recipientDomain)) { return part + '>' + recipientDomain; } else if (SET.contains(part + ';' + validation)) { return part + ';' + validation; } else if (SET.contains(part + ';' + validation + '>' + recipient)) { return part + ';' + validation + '>' + recipient; } else if (SET.contains(part + ';' + validation + '>' + recipientDomain)) { return part + ';' + validation + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + part)) { return userEmail + ':' + part; } else if (userEmail != null && SET.contains(userEmail + ':' + part + '>' + recipient)) { return userEmail + ':' + part + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + part + '>' + recipientDomain)) { return userEmail + ':' + part + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + part + ';' + validation)) { return userEmail + ':' + part + ';' + validation; } else if (userEmail != null && SET.contains(userEmail + ':' + part + ';' + validation + '>' + recipient)) { return userEmail + ':' + part + ';' + validation + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + part + ';' + validation + '>' + recipientDomain)) { return userEmail + ':' + part + ';' + validation + '>' + recipientDomain; } else if (SET.contains(senderDomain)) { return senderDomain; } else if (SET.contains(senderDomain + '>' + recipient)) { return senderDomain + '>' + recipient; } else if (SET.contains(senderDomain + '>' + recipientDomain)) { return senderDomain + '>' + recipientDomain; } else if (SET.contains(senderDomain + ';' + validation)) { return senderDomain + ';' + validation; } else if (SET.contains(senderDomain + ';' + validation + '>' + recipient)) { return senderDomain + ';' + validation + '>' + recipient; } else if (SET.contains(senderDomain + ';' + validation + '>' + recipientDomain)) { return senderDomain + ';' + validation + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain)) { return userEmail + ':' + senderDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain + '>' + recipient)) { return userEmail + ':' + senderDomain + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain + '>' + recipientDomain)) { return userEmail + ':' + senderDomain + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain + ';' + validation)) { return userEmail + ':' + senderDomain + ';' + validation; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain + ';' + validation + '>' + recipient)) { return userEmail + ':' + senderDomain + ';' + validation + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + senderDomain + ';' + validation + '>' + recipientDomain)) { return userEmail + ':' + senderDomain + ';' + validation + '>' + recipientDomain; } else if ((host = findHost(userEmail, sender, "." + senderDomain.substring(1), validation, recipient, recipientDomain, whoisSet, regexSet, false)) != null) { return host; } else if (recipient != null && SET.contains("@>" + recipient)) { return "@>" + recipient; } else if (recipientDomain != null && SET.contains("@>" + recipientDomain)) { return "@>" + recipientDomain; } else if (recipient != null && userEmail != null && SET.contains(userEmail + ":@>" + recipient)) { return userEmail + ":@>" + recipient; } else if (recipientDomain != null && userEmail != null && SET.contains(userEmail + ":@>" + recipientDomain)) { return userEmail + ":@>" + recipientDomain; } else if (recipient != null && SET.contains("@;" + validation)) { return "@;" + validation; } else if (recipient != null && SET.contains("@;" + validation + ">" + recipient)) { return "@;" + validation + ">" + recipient; } else if (recipientDomain != null && SET.contains("@;" + validation + ">" + recipientDomain)) { return "@;" + validation + ">" + recipientDomain; } else if (recipient != null && userEmail != null && SET.contains(userEmail + ":@;" + validation)) { return userEmail + ":@;" + validation; } else if (recipient != null && userEmail != null && SET.contains(userEmail + ":@;" + validation + ">" + recipient)) { return userEmail + ":@;" + validation + ">" + recipient; } else if (recipientDomain != null && userEmail != null && SET.contains(userEmail + ":@;" + validation + ">" + recipientDomain)) { return userEmail + ":@;" + validation + ">" + recipientDomain; } else { int index3 = senderDomain.length(); while ((index3 = senderDomain.lastIndexOf('.', index3 - 1)) > index2) { String subdomain = senderDomain.substring(0, index3 + 1); if (SET.contains(subdomain)) { return subdomain; } else if (SET.contains(subdomain + '>' + recipient)) { return subdomain + '>' + recipient; } else if (SET.contains(subdomain + '>' + recipientDomain)) { return subdomain + '>' + recipientDomain; } else if (SET.contains(subdomain + ';' + validation)) { return subdomain + ';' + validation; } else if (SET.contains(subdomain + ';' + validation + '>' + recipient)) { return subdomain + ';' + validation + '>' + recipient; } else if (SET.contains(subdomain + ';' + validation + '>' + recipientDomain)) { return subdomain + ';' + validation + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + subdomain)) { return userEmail + ':' + subdomain; } else if (userEmail != null && SET.contains(userEmail + ':' + subdomain + '>' + recipient)) { return userEmail + ':' + subdomain + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + subdomain + '>' + recipientDomain)) { return userEmail + ':' + subdomain + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + subdomain + ';' + validation)) { return userEmail + ':' + subdomain + ';' + validation; } else if (userEmail != null && SET.contains(userEmail + ':' + subdomain + ';' + validation + '>' + recipient)) { return userEmail + ':' + subdomain + ';' + validation + '>' + recipient; } else if (userEmail != null && SET .contains(userEmail + ':' + subdomain + ';' + validation + '>' + recipientDomain)) { return userEmail + ':' + subdomain + ';' + validation + '>' + recipientDomain; } } int index4 = sender.length(); while ((index4 = sender.lastIndexOf('.', index4 - 1)) > index2) { String subsender = sender.substring(0, index4 + 1); if (SET.contains(subsender)) { return subsender; } else if (SET.contains(subsender + '>' + recipient)) { return subsender + '>' + recipient; } else if (SET.contains(subsender + '>' + recipientDomain)) { return subsender + '>' + recipientDomain; } else if (SET.contains(subsender + ';' + validation)) { return subsender + ';' + validation; } else if (SET.contains(subsender + ';' + validation + '>' + recipient)) { return subsender + ';' + validation + '>' + recipient; } else if (SET.contains(subsender + ';' + validation + '>' + recipientDomain)) { return subsender + ';' + validation + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + subsender)) { return userEmail + ':' + subsender; } else if (userEmail != null && SET.contains(userEmail + ':' + subsender + '>' + recipient)) { return userEmail + ':' + subsender + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + subsender + '>' + recipientDomain)) { return userEmail + ':' + subsender + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + subsender + ';' + validation)) { return userEmail + ':' + subsender + ';' + validation; } else if (userEmail != null && SET.contains(userEmail + ':' + subsender + ';' + validation + '>' + recipient)) { return userEmail + ':' + subsender + ';' + validation + '>' + recipient; } else if (userEmail != null && SET .contains(userEmail + ':' + subsender + ';' + validation + '>' + recipientDomain)) { return userEmail + ':' + subsender + ';' + validation + '>' + recipientDomain; } } } if (senderDomain.endsWith(".br")) { whoisSet.add(senderDomain); } regexSet.add(sender); regexSet.add(senderDomain); } return null; } public static boolean containsHREF(String token) { if (Subnet.isValidIP(token)) { String ip = Subnet.normalizeIP(token); return SET.contains("HREF=" + ip); } else if (Domain.isHostname(token)) { String host = Domain.normalizeHostname(token, true); do { int index = host.indexOf('.') + 1; host = host.substring(index); String token2 = '.' + host; if (SET.contains("HREF=" + token2)) { return true; } } while (host.contains(".")); String ownerID = Domain.getOwnerID(token); if (ownerID != null) { if (SET.contains("HREF=" + ownerID)) { if (SET.addExact("HREF=" + token)) { Server.logDebug("new BLOCK 'HREF=" + token + "' added by 'HREF=" + ownerID + "'."); } return true; } } } return false; } public static boolean containsCIDR(String ip) { if ((ip = Subnet.normalizeIP(ip)) == null) { return false; } else { return CIDR.get(null, ip) != null; } } public static boolean containsDNSBL(String ip) { if ((ip = Subnet.normalizeIP(ip)) == null) { return false; } else { return DNSBL.get(null, ip) != null; } } private static int parseIntWHOIS(String value) { try { if (value == null || value.length() == 0) { return 0; } else { Date date = new SimpleDateFormat("yyyyMMdd").parse(value); long time = date.getTime() / (1000 * 60 * 60 * 24); long today = System.currentTimeMillis() / (1000 * 60 * 60 * 24); return (int) (today - time); } } catch (Exception ex) { try { return Integer.parseInt(value); } catch (Exception ex2) { return 0; } } } public static boolean containsDomain(String host, boolean href) { return containsDomain(null, host, href); } public static boolean containsDomain(String client, String host, boolean href) { host = Domain.extractHost(host, true); if (host == null) { return false; } else { do { int index = host.indexOf('.') + 1; host = host.substring(index); String token = '.' + host; if (SET.contains(token)) { return true; } else if (client != null && SET.contains(client + ':' + token)) { return true; } } while (host.contains(".")); return false; } } public static boolean containsREGEX(String host) throws ProcessException { host = Domain.extractHost(host, true); if (host == null) { return false; } else { LinkedList<String> tokenList = new LinkedList<String>(); do { int index = host.indexOf('.') + 1; host = host.substring(index); String token = '.' + host; tokenList.addFirst(token); } while (host.contains(".")); return REGEX.get(null, tokenList, true) != null; } } public static boolean containsWHOIS(String host) throws ProcessException { host = Domain.extractHost(host, true); if (host == null) { return false; } else if (host.endsWith(".br")) { try { TreeSet<String> tokenSet = new TreeSet<String>(); tokenSet.add(host); return WHOIS.get(null, tokenSet, true) != null; } catch (Exception ex) { Server.logError(ex); return false; } } else { return false; } } private static String findHost(String userEmail, String sender, String hostname, String qualifier, String recipient, String recipientDomain, TreeSet<String> whoisSet, TreeSet<String> regexSet, boolean full) { hostname = Domain.extractHost(hostname, true); if (hostname == null) { return null; } else { do { int index = hostname.indexOf('.') + 1; hostname = hostname.substring(index); String token = '.' + hostname; if (SET.contains(token)) { return token; } else if (SET.contains(token + '>' + recipient)) { return token + '>' + recipient; } else if (SET.contains(token + '>' + recipientDomain)) { return token + '>' + recipientDomain; } else if (SET.contains(token + ';' + qualifier)) { return token + ';' + qualifier; } else if (SET.contains(token + ';' + qualifier + '>' + recipient)) { return token + ';' + qualifier + '>' + recipient; } else if (SET.contains(token + ';' + qualifier + '>' + recipientDomain)) { return token + ';' + qualifier + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ":@;" + token)) { return userEmail + ":@;" + token; } else if (userEmail != null && SET.contains(userEmail + ':' + token)) { return userEmail + ':' + token; } else if (userEmail != null && SET.contains(userEmail + ':' + token + '>' + recipient)) { return userEmail + ':' + token + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + token + '>' + recipientDomain)) { return userEmail + ':' + token + '>' + recipientDomain; } else if (userEmail != null && SET.contains(userEmail + ':' + token + ';' + qualifier)) { return userEmail + ':' + token + ';' + qualifier; } else if (userEmail != null && SET.contains(userEmail + ':' + token + ';' + qualifier + '>' + recipient)) { return userEmail + ':' + token + ';' + qualifier + '>' + recipient; } else if (userEmail != null && SET.contains(userEmail + ':' + token + ';' + qualifier + '>' + recipientDomain)) { return userEmail + ':' + token + ';' + qualifier + '>' + recipientDomain; } else if (full && (token = findSender(userEmail, sender, hostname, recipient, recipientDomain, whoisSet, regexSet)) != null) { return token; } } while (hostname.contains(".")); return null; } } public static void store(boolean simplify) { if (CHANGED) { if (simplify) { Server.logTrace("simplifing block.set"); CIDR.simplify(); } try { // Server.logTrace("storing block.set"); long time = System.currentTimeMillis(); File file = new File("./data/block.set"); TreeSet<String> tokenSet = getAll(); FileOutputStream outputStream = new FileOutputStream(file); try { SerializationUtils.serialize(tokenSet, outputStream); CHANGED = false; } finally { outputStream.close(); } Server.logStore(time, file); } catch (Exception ex) { Server.logError(ex); } try { // Server.logTrace("storing block.map"); long time = System.currentTimeMillis(); File file = new File("./data/block.map"); TreeMap<String, Long> tokenMap = SET.getMap(); FileOutputStream outputStream = new FileOutputStream(file); try { SerializationUtils.serialize(tokenMap, outputStream); CHANGED = false; } finally { outputStream.close(); } Server.logStore(time, file); } catch (Exception ex) { Server.logError(ex); } } } public static void load() { long time = System.currentTimeMillis(); File file = new File("./data/block.set"); if (file.exists()) { try { Set<String> set; FileInputStream fileInputStream = new FileInputStream(file); try { set = SerializationUtils.deserialize(fileInputStream); } finally { fileInputStream.close(); } for (String token : set) { String client; String identifier; if (token.contains(":")) { int index = token.indexOf(':'); client = token.substring(0, index); if (Domain.isEmail(client)) { identifier = token.substring(index + 1); } else { client = null; identifier = token; } } else { client = null; identifier = token; } if (identifier.startsWith("CIDR=")) { CIDR.addExact(client, identifier); } else if (identifier.startsWith("WHOIS/")) { WHOIS.addExact(client, identifier); } else if (identifier.startsWith("DNSBL=")) { DNSBL.addExact(client, identifier); } else if (identifier.startsWith("REGEX=")) { REGEX.addExact(client, identifier); } else { SET.addExact(token); } } CHANGED = false; Server.logLoad(time, file); } catch (Exception ex) { Server.logError(ex); } } time = System.currentTimeMillis(); file = new File("./data/block.map"); if (file.exists()) { try { Map<String, Long> map; FileInputStream fileInputStream = new FileInputStream(file); try { map = SerializationUtils.deserialize(fileInputStream); } finally { fileInputStream.close(); } for (String token : map.keySet()) { Long last = map.get(token); if (last != null) { SET.putExact(token, last); } } CHANGED = false; Server.logLoad(time, file); } catch (Exception ex) { Server.logError(ex); } } } }