FairEmail/app/src/main/java/eu/faircode/email/DnsBlockList.java

194 lines
6.8 KiB
Java
Raw Normal View History

2021-06-19 08:00:38 +00:00
package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail 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.
FairEmail 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 FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018-2021 by Marcel Bokhorst (M66B)
*/
import android.text.TextUtils;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
2021-06-19 15:23:35 +00:00
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
2021-06-19 08:00:38 +00:00
import java.util.Date;
import java.util.Hashtable;
2021-06-19 15:23:35 +00:00
import java.util.List;
2021-06-19 08:00:38 +00:00
import java.util.Map;
public class DnsBlockList {
2021-06-19 15:23:35 +00:00
static final List<BlockList> BLOCKLISTS = Collections.unmodifiableList(Arrays.asList(
new BlockList("zen.spamhaus.org", new String[]{
//https://www.spamhaus.org/faq/section/DNSBL%20Usage#200
"127.0.0.2", // SBL Spamhaus SBL Data
"127.0.0.3", // SBL Spamhaus SBL CSS Data
"127.0.0.4", // XBL CBL Data
"127.0.0.9" // SBL Spamhaus DROP/EDROP Data
//127.0.0.10 PBL ISP Maintained
//127.0.0.11 PBL Spamhaus Maintained
}),
new BlockList("bl.spamcop.net", new String[]{
// https://www.spamcop.net/fom-serve/cache/291.html
"127.0.0.2"
})
2021-06-19 17:06:29 +00:00
//new BlockList("b.barracudacentral.org", new String[]{
// // https://www.barracudacentral.org/rbl/how-to-use
//})
2021-06-19 15:23:35 +00:00
));
2021-06-19 08:00:38 +00:00
private static final long CACHE_EXPIRY_AFTER = 3600 * 1000L; // milliseconds
2021-06-19 15:23:35 +00:00
private static final Map<String, CacheEntry> cache = new Hashtable<>();
2021-06-19 08:00:38 +00:00
static boolean isJunk(String email) {
if (TextUtils.isEmpty(email))
return false;
2021-06-19 15:23:35 +00:00
2021-06-19 08:00:38 +00:00
int at = email.indexOf('@');
if (at < 0)
return false;
2021-06-19 15:23:35 +00:00
return isJunk(email.substring(at + 1), BLOCKLISTS);
2021-06-19 08:00:38 +00:00
}
2021-06-19 15:23:35 +00:00
private static boolean isJunk(String domain, List<BlockList> blocklists) {
synchronized (cache) {
CacheEntry entry = cache.get(domain);
if (entry != null && !entry.isExpired())
return entry.isJunk();
}
2021-06-19 08:00:38 +00:00
boolean blocked = false;
2021-06-19 15:23:35 +00:00
for (BlockList blocklist : blocklists)
if (isJunk(domain, blocklist)) {
blocked = true;
break;
}
synchronized (cache) {
cache.put(domain, new CacheEntry(blocked));
}
return blocked;
}
private static boolean isJunk(String domain, BlockList blocklist) {
2021-06-19 08:00:38 +00:00
try {
2021-06-19 17:06:29 +00:00
long start = new Date().getTime();
2021-06-19 15:23:35 +00:00
InetAddress[] addresses = InetAddress.getAllByName(domain);
2021-06-19 17:06:29 +00:00
long elapsed = new Date().getTime() - start;
Log.i("isJunk resolved=" + domain + " elapse=" + elapsed + " ms");
2021-06-19 15:23:35 +00:00
for (InetAddress addr : addresses)
2021-06-19 08:00:38 +00:00
try {
StringBuilder lookup = new StringBuilder();
if (addr instanceof Inet4Address) {
byte[] a = addr.getAddress();
for (int i = 3; i >= 0; i--)
lookup.append(a[i] & 0xff).append('.');
} else if (addr instanceof Inet6Address) {
byte[] a = addr.getAddress();
for (int i = 15; i >= 0; i--) {
int b = a[i] & 0xff;
lookup.append(String.format("%01x", b & 0xf)).append('.');
lookup.append(String.format("%01x", b >> 4)).append('.');
}
}
2021-06-19 15:23:35 +00:00
lookup.append(blocklist.address);
2021-06-19 08:00:38 +00:00
2021-06-19 17:06:29 +00:00
start = new Date().getTime();
2021-06-19 08:00:38 +00:00
InetAddress result;
try {
2021-06-19 15:23:35 +00:00
// Possibly blocked
2021-06-19 08:00:38 +00:00
result = InetAddress.getByName(lookup.toString());
} catch (UnknownHostException ignored) {
// Not blocked
result = null;
}
2021-06-19 17:06:29 +00:00
elapsed = new Date().getTime() - start;
2021-06-19 15:23:35 +00:00
2021-06-19 17:06:29 +00:00
if (result != null && blocklist.responses.length > 0) {
boolean blocked = false;
2021-06-19 15:23:35 +00:00
for (InetAddress response : blocklist.responses)
if (response.equals(result)) {
2021-06-19 17:06:29 +00:00
blocked = true;
2021-06-19 15:23:35 +00:00
break;
}
2021-06-19 17:06:29 +00:00
if (!blocked) {
2021-06-19 15:23:35 +00:00
Log.w("isJunk" +
" addr=" + addr +
" lookup=" + lookup +
" result=" + result +
" elapsed=" + elapsed);
2021-06-19 17:06:29 +00:00
result = null;
2021-06-19 15:23:35 +00:00
}
2021-06-19 08:00:38 +00:00
}
2021-06-19 15:23:35 +00:00
Log.i("isJunk " + addr +
" " + lookup + "=" + (result == null ? "false" : result) +
" elapsed=" + elapsed);
2021-06-19 08:00:38 +00:00
if (result != null)
2021-06-19 15:23:35 +00:00
return true;
2021-06-19 08:00:38 +00:00
} catch (Throwable ex) {
Log.w(ex);
}
} catch (Throwable ex) {
Log.w(ex);
}
2021-06-19 15:23:35 +00:00
return false;
2021-06-19 08:00:38 +00:00
}
private static class CacheEntry {
private final long time;
2021-06-19 15:23:35 +00:00
private final boolean blocked;
2021-06-19 08:00:38 +00:00
2021-06-19 15:23:35 +00:00
CacheEntry(boolean blocked) {
2021-06-19 08:00:38 +00:00
this.time = new Date().getTime();
2021-06-19 15:23:35 +00:00
this.blocked = blocked;
2021-06-19 08:00:38 +00:00
}
boolean isExpired() {
return (new Date().getTime() - this.time) > CACHE_EXPIRY_AFTER;
}
boolean isJunk() {
2021-06-19 15:23:35 +00:00
return blocked;
}
}
static class BlockList {
String address;
InetAddress[] responses;
BlockList(String address, String[] responses) {
this.address = address;
List<InetAddress> r = new ArrayList<>();
for (String response : responses)
try {
r.add(InetAddress.getByName(response));
} catch (UnknownHostException ex) {
Log.e(ex);
}
this.responses = r.toArray(new InetAddress[0]);
2021-06-19 08:00:38 +00:00
}
}
}