diff --git a/com.openexchange.mail.autoconfig.impl/META-INF/MANIFEST.MF b/com.openexchange.mail.autoconfig.impl/META-INF/MANIFEST.MF index d88434c147d3db144cdf2f8f3bcf5724faaef7e8..ab841d4aa0d64b163edc07264abffec231279d87 100644 --- a/com.openexchange.mail.autoconfig.impl/META-INF/MANIFEST.MF +++ b/com.openexchange.mail.autoconfig.impl/META-INF/MANIFEST.MF @@ -33,6 +33,7 @@ Import-Package: com.google.common.annotations, com.openexchange.mail.mime, com.openexchange.mail.utils, com.openexchange.mailaccount, + com.openexchange.mailaccount.utils, com.openexchange.net, com.openexchange.net.ssl, com.openexchange.net.ssl.config, diff --git a/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/sources/Guess.java b/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/sources/Guess.java index 428179310ae30b6a3762d4e4e69018ae97a4ac3a..bd557181d1276d46a6f9444bc272b4adb2f958db 100644 --- a/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/sources/Guess.java +++ b/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/sources/Guess.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import com.openexchange.config.cascade.ComposedConfigProperty; import com.openexchange.config.cascade.ConfigView; import com.openexchange.config.cascade.ConfigViewFactory; @@ -45,13 +46,13 @@ import com.openexchange.tools.net.URIDefaults; public class Guess extends AbstractConfigSource { static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Guess.class); - + /** The property name for context identifier. Value is <code>java.lang.Integer</code> */ public static final String PROP_GENERAL_CONTEXT_ID = "general.context"; - + /** The property name for user identifier. Value is <code>java.lang.Integer</code> */ public static final String PROP_GENERAL_USER_ID = "general.user"; - + /** The property name for flag whether SMTP supports authentication. Value is <code>java.lang.Boolean</code> */ public static final String PROP_SMTP_AUTH_SUPPORTED = "smtp.auth-supported"; @@ -113,13 +114,15 @@ public class Guess extends AbstractConfigSource { } private boolean fillProtocol(Protocol protocol, String emailLocalPart, String emailDomain, String password, DefaultAutoconfig config, Map<String, Object> properties, boolean forceSecure) { - ConnectSettings connectSettings = guessHost(protocol, emailDomain); - if (connectSettings == null) { + Optional<ConnectSettings> optConnectSettings = guessHost(protocol, emailDomain); + if (optConnectSettings.isPresent() == false) { return false; } - String login = guessLogin(protocol, connectSettings.host, connectSettings.port, connectSettings.secure, forceSecure, emailLocalPart, emailDomain, password, properties); - if (login == null) { + ConnectSettings connectSettings = optConnectSettings.get(); + + Optional<String> optLogin = guessLogin(protocol, connectSettings.host, connectSettings.port, connectSettings.secure, forceSecure, emailLocalPart, emailDomain, password, properties); + if (optLogin.isPresent() == false) { return false; } @@ -129,19 +132,19 @@ public class Guess extends AbstractConfigSource { config.setTransportSecure(connectSettings.secure); config.setTransportServer(connectSettings.host); config.setTransportStartTls(forceSecure); // Take over since end-point has been checked with proper STARTTLS setting if we reach this point - config.setUsername(login); + config.setUsername(optLogin.get()); } else { config.setMailPort(connectSettings.port); config.setMailProtocol(protocol.getProtocol()); config.setMailSecure(connectSettings.secure); config.setMailServer(connectSettings.host); config.setMailStartTls(forceSecure); // Take over since end-point has been checked with proper STARTTLS setting if we reach this point - config.setUsername(login); + config.setUsername(optLogin.get()); } return true; } - private String guessLogin(Protocol protocol, String host, int port, boolean secure, boolean requireTls, String emailLocalPart, String emailDomain, String password, Map<String, Object> properties) { + private Optional<String> guessLogin(Protocol protocol, String host, int port, boolean secure, boolean requireTls, String emailLocalPart, String emailDomain, String password, Map<String, Object> properties) { List<String> logins = Arrays.asList(emailLocalPart, emailLocalPart+"@"+emailDomain); ConnectMode connectMode = ConnectMode.connectModeFor(secure, requireTls); @@ -149,34 +152,33 @@ public class Guess extends AbstractConfigSource { switch (protocol) { case IMAP: if (MailValidator.validateImap(host, port, connectMode, login, password, properties)) { - return login; + Optional.ofNullable(login); } break; case POP3: if (MailValidator.validatePop3(host, port, connectMode, login, password, properties)) { - return login; + Optional.ofNullable(login); } break; case SMTP: if (MailValidator.validateSmtp(host, port, connectMode, login, password, properties)) { - return login; + return Optional.ofNullable(login); } break; } } - return null; + return Optional.empty(); } private static final List<String> IMAP_PREFIXES = Arrays.asList("", "imap.", "mail."); private static final List<String> SMTP_PREFIXES = Arrays.asList("", "smtp.", "mail."); private static final List<String> POP3_PREFIXES = Arrays.asList("", "pop3.", "mail."); - private ConnectSettings guessHost(Protocol protocol, String emailDomain) { - URIDefaults uriDefaults = null; - List<String> prefixes = null; + private Optional<ConnectSettings> guessHost(Protocol protocol, String emailDomain) { + URIDefaults uriDefaults; int altPort = 0; - + List<String> prefixes; switch (protocol) { case IMAP: prefixes = IMAP_PREFIXES; @@ -192,34 +194,34 @@ public class Guess extends AbstractConfigSource { uriDefaults = URIDefaults.SMTP; break; default: - return null; + return Optional.empty(); } for (String prefix : prefixes) { - String host = prefix + emailDomain; + String host = prefix.length() > 0 ? prefix + emailDomain : emailDomain; // Try SSL connect using default SSL port if (tryConnect(protocol, host, uriDefaults.getSSLPort(), true)) { - return new ConnectSettings(host, true, uriDefaults.getSSLPort()); + return Optional.of(new ConnectSettings(host, true, uriDefaults.getSSLPort())); } // Try SSL connect using default port if (tryConnect(protocol, host, uriDefaults.getPort(), true)) { - return new ConnectSettings(host, true, uriDefaults.getPort()); + return Optional.of(new ConnectSettings(host, true, uriDefaults.getPort())); } // Try plain connect using alternative port if (altPort > 0 && tryConnect(protocol, host, altPort, false)) { - return new ConnectSettings(host, false, altPort); + return Optional.of(new ConnectSettings(host, false, altPort)); } // Try plain connect using default port if (tryConnect(protocol, host, uriDefaults.getPort(), false)) { - return new ConnectSettings(host, false, uriDefaults.getPort()); + return Optional.of(new ConnectSettings(host, false, uriDefaults.getPort())); } } - return null; + return Optional.empty(); } private boolean tryConnect(Protocol protocol, String emailDomain, int port, boolean secure) { diff --git a/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/tools/MailValidator.java b/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/tools/MailValidator.java index 0cafeaf80192409e8d9400f55f870138048d905c..bf67f6a45718392f76dbfc23baa3adda09dc4d6b 100644 --- a/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/tools/MailValidator.java +++ b/com.openexchange.mail.autoconfig.impl/src/com/openexchange/mail/autoconfig/tools/MailValidator.java @@ -43,6 +43,7 @@ import com.openexchange.java.Streams; import com.openexchange.java.Strings; import com.openexchange.mail.mime.MimeDefaultSession; import com.openexchange.mail.utils.NetUtils; +import com.openexchange.mailaccount.utils.MailAccountUtils; import com.openexchange.net.ssl.SSLSocketFactoryProvider; import com.openexchange.net.ssl.config.SSLConfigurationService; import com.sun.mail.smtp.SMTPTransport; @@ -326,8 +327,15 @@ public class MailValidator { private static boolean tryConnect(String host, int port, boolean secure, String closePhrase, String name) { Socket s = null; try { + // Check if black-listed + if (MailAccountUtils.isDenied(host, port)) { + return false; + } + // Establish socket connection - s = SocketFetcher.getSocket(host, port, createProps(name, port, secure), "mail." + name, false); + Properties props = createProps(name, port, secure); + props.put("mail." + name + ".denyInternalAddress", "true"); + s = SocketFetcher.getSocket(host, port, props, "mail." + name, false); InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); if (null == in || null == out) { diff --git a/com.openexchange.server/META-INF/MANIFEST.MF b/com.openexchange.server/META-INF/MANIFEST.MF index 88136627db1be720dec78a5c99a28d86a3bb26af..30dcae44b014e5a5f2247aa344aafd22267241e8 100644 --- a/com.openexchange.server/META-INF/MANIFEST.MF +++ b/com.openexchange.server/META-INF/MANIFEST.MF @@ -683,6 +683,7 @@ Export-Package: com.openexchange.ajax, com.openexchange.mailaccount.json, com.openexchange.mailaccount.json.parser, com.openexchange.mailaccount.json.writer, + com.openexchange.mailaccount.utils, com.openexchange.multiple, com.openexchange.passwordchange, com.openexchange.policy.retry, diff --git a/javax.mail/src/com/sun/mail/util/SocketFetcher.java b/javax.mail/src/com/sun/mail/util/SocketFetcher.java index 51cc0e67df62f2794518d50bbc81b624a8875268..4fbcbd5e3511f06743078cd07ae2aac08da0a88a 100644 --- a/javax.mail/src/com/sun/mail/util/SocketFetcher.java +++ b/javax.mail/src/com/sun/mail/util/SocketFetcher.java @@ -176,24 +176,57 @@ public class SocketFetcher { private static Socket getSocket(String host, int port, Properties props, String prefix, boolean useSSL, boolean retryOnNoRouteToHost) throws IOException { try { + boolean denyInternalAddress = PropUtil.getBooleanProperty(props, prefix + ".denyInternalAddress", false); + InetAddress[] addresses = InetAddress.getAllByName(host); if (addresses.length == 1 || !PropUtil.getBooleanProperty(props, prefix + ".multiAddress.enabled", false)) { + if (denyInternalAddress && com.openexchange.java.InetAddresses.isInternalAddress(addresses[0])) { + throw new IOException("Denied to connect against internal address: " + host); + } return getSocket(addresses[0], host, port, props, prefix, useSSL); } - + + if (denyInternalAddress) { + java.util.List<InetAddress> validAddresses = null; + for (int i = 0; i < addresses.length; i++) { + boolean denied = com.openexchange.java.InetAddresses.isInternalAddress(addresses[i]); + if (validAddresses == null) { + if (denied) { + validAddresses = new java.util.ArrayList<>(addresses.length); + if (i > 0) { + // Add previous addresses to valid ones + for (int k = 0; k < i; k++) { + validAddresses.add(addresses[k]); + } + } + } + } else { + if (denied == false) { + validAddresses.add(addresses[i]); + } + } + } + if (validAddresses != null) { + if (validAddresses.isEmpty()) { + throw new IOException("Denied to connect against internal address: " + host); + } + addresses = validAddresses.toArray(new InetAddress[validAddresses.size()]); + } + } + AddressSelector selector = AddressSelector.getSelectorFor(host, addresses, props, prefix); return new FailoverSocket(selector, host, port, props, prefix, useSSL); } catch (java.net.UnknownHostException e) { throw e; } catch (IOException e) { - if (retryOnNoRouteToHost == false || isNoRouteToHostException(e) == false) { + if (retryOnNoRouteToHost == false || isNoRouteToHostException(e) == false) { throw e; } - + if (clearDnsCache() == false) { throw e; } - + return getSocket(host, port, props, prefix, useSSL, false); } }