Experiment: TLS detection

This commit is contained in:
M66B 2022-01-06 22:28:22 +01:00
parent 84f7df5099
commit 41eefbe3b4
4 changed files with 123 additions and 0 deletions

View File

@ -101,6 +101,8 @@ public class ConnectionHelper {
public static native int jni_socket_get_send_buffer(int fd);
public static native boolean jni_is_numeric_address(String _ip);
static class NetworkState {
private Boolean connected = null;
private Boolean suitable = null;

View File

@ -3738,6 +3738,9 @@ class Core {
if (received == null)
received = 0L;
if (BuildConfig.DEBUG)
Log.i("--- TLS=" + helper.getTLS());
String[] authentication = helper.getAuthentication();
MessageHelper.MessageParts parts = helper.getMessageParts();

View File

@ -66,7 +66,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.IDN;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
@ -1914,6 +1916,95 @@ public class MessageHelper {
return null;
}
Boolean getTLS() throws MessagingException {
// https://datatracker.ietf.org/doc/html/rfc2821#section-4.4
// Time-stamp-line = "Received:" FWS Stamp <CRLF>
// Stamp = From-domain By-domain Opt-info ";" FWS date-time
// From-domain = "FROM" FWS Extended-Domain CFWS
// By-domain = "BY" FWS Extended-Domain CFWS
// Opt-info = [Via] [With] [ID] [For]
// Via = "VIA" FWS Link CFWS
// With = "WITH" FWS Protocol CFWS
// ID = "ID" FWS String / msg-id CFWS
// For = "FOR" FWS 1*( Path / Mailbox ) CFWS
// Extended-Domain = Domain / ( Domain FWS "(" TCP-info ")" ) / ( Address-literal FWS "(" TCP-info ")" )
// TCP-info = Address-literal / ( Domain FWS Address-literal )
// Link = "TCP" / Addtl-Link
// Addtl-Link = Atom
// Protocol = "ESMTP" / "SMTP" / Attdl-Protocol
// Attdl-Protocol = Atom
String[] received = imessage.getHeader("Received");
if (received == null || received.length == 0)
return null;
final List<String> words = Collections.unmodifiableList(Arrays.asList(
"from", "by", "via", "with", "id", "for"));
// First header is last added header
for (String r : received) {
String header = MimeUtility.unfold(r);
int s, e;
do {
s = header.indexOf('(');
e = header.indexOf(')', s);
if (s > 0 && e > 0)
header = header.substring(0, s) + header.substring((e + 1));
} while (s > 0 && e > 0);
int semi = header.lastIndexOf(';');
if (semi > 0)
header = header.substring(0, semi);
header = header.replaceAll("\\s+", " ");
Log.i("--- header=" + header);
String[] parts = header.split(" ");
boolean hasFrom = false;
boolean hasWith = false;
for (int j = 0; j < parts.length - 1; j++) {
Log.i("--- part " + j + " " + parts[j] + "=" + parts[j + 1]);
if ("from".equalsIgnoreCase(parts[j])) {
hasFrom = true;
String from = parts[j + 1].toLowerCase(Locale.ROOT);
boolean numeric = ConnectionHelper.jni_is_numeric_address(from);
Log.i("--- numeric=" + numeric);
if (numeric)
try {
InetAddress addr = InetAddress.getByName(from);
if (addr.isSiteLocalAddress())
break;
Log.i("--- remote");
} catch (UnknownHostException ex) {
Log.e(ex);
}
} else if ("with".equalsIgnoreCase(parts[j])) {
hasWith = true;
if (hasFrom) {
String with = parts[j + 1].toUpperCase(Locale.ROOT);
Log.i("--- MTP=" + with.contains("MTP") + " MTPS=" + with.contains("MTPS"));
// https://www.iana.org/assignments/mail-parameters/mail-parameters.txt
if (!with.contains("MTP"))
return null;
if (!with.contains("MTPS"))
return false;
}
break;
}
if (words.contains(parts[j]))
j++;
}
if (hasFrom && !hasWith)
return null;
}
return true;
}
Long getSent() throws MessagingException {
ensureEnvelope();

View File

@ -157,3 +157,30 @@ Java_eu_faircode_email_ConnectionHelper_jni_1socket_1get_1send_1buffer(
log_android(ANDROID_LOG_DEBUG, "ioctl(TIOCOUTQ) res=%d queued=%d", res, queued);
return (res == 0 ? queued : 0);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_eu_faircode_email_ConnectionHelper_jni_1is_1numeric_1address(
JNIEnv *env, jclass clazz,
jstring _ip) {
jboolean numeric = 0;
const char *ip = env->GetStringUTFChars(_ip, 0);
// https://linux.die.net/man/3/getaddrinfo
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST; // suppresses any potentially lengthy network host address lookups
struct addrinfo *result;
int err = getaddrinfo(ip, nullptr, &hints, &result);
if (err)
log_android(ANDROID_LOG_DEBUG, "getaddrinfo(%s) error %d: %s", ip, err, gai_strerror(err));
else
numeric = (jboolean) (result != nullptr);
if (result != nullptr)
freeaddrinfo(result);
env->ReleaseStringUTFChars(_ip, ip);
return numeric;
}