Author: norman Date: Fri May 19 08:17:40 2006 New Revision: 407822 URL: http://svn.apache.org/viewvc?rev=407822&view=rev Log: Add new feature to reject email when HELO/EHLO not equals reverse of the client ip. See JAMES-463
Modified: james/server/trunk/src/conf/james-config.xml james/server/trunk/src/java/org/apache/james/smtpserver/EhloCmdHandler.java james/server/trunk/src/java/org/apache/james/smtpserver/HeloCmdHandler.java james/server/trunk/src/test/org/apache/james/smtpserver/SMTPServerTest.java james/server/trunk/src/test/org/apache/james/smtpserver/SMTPTestConfiguration.java Modified: james/server/trunk/src/conf/james-config.xml URL: http://svn.apache.org/viewvc/james/server/trunk/src/conf/james-config.xml?rev=407822&r1=407821&r2=407822&view=diff ============================================================================== --- james/server/trunk/src/conf/james-config.xml (original) +++ james/server/trunk/src/conf/james-config.xml Fri May 19 08:17:40 2006 @@ -727,6 +727,12 @@ <checkResolvableHelo> false </checkResolvableHelo> --> + <!-- If is set to true helo is only accepted if it is equal the reverse of the --> + <!-- connecting client --> + <!-- + <checkReverseEqualsHelo> false </checkReverseEqualsHelo> + --> + <!-- If is set to true sender domain will be checked also for clients that --> <!-- are allowed to relay. Default is false. --> <!-- @@ -737,6 +743,12 @@ <!-- If is set to true ehlo is only accepted if it can be resolved --> <!-- <checkResolvableEhlo> false </checkResolvableEhlo> + --> + + <!-- If is set to true ehlo is only accepted if it is equal the reverse of the --> + <!-- connecting client --> + <!-- + <checkReverseEqualsEhlo> false </checkReverseEqualsEhlo> --> <!-- If is set to true sender domain will be checked also for clients that --> Modified: james/server/trunk/src/java/org/apache/james/smtpserver/EhloCmdHandler.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/smtpserver/EhloCmdHandler.java?rev=407822&r1=407821&r2=407822&view=diff ============================================================================== --- james/server/trunk/src/java/org/apache/james/smtpserver/EhloCmdHandler.java (original) +++ james/server/trunk/src/java/org/apache/james/smtpserver/EhloCmdHandler.java Fri May 19 08:17:40 2006 @@ -44,6 +44,8 @@ * set checkResolvableEhlo to false as default value */ private boolean checkResolvableEhlo = false; + + private boolean checkReverseEqualsEhlo = false; private boolean checkAuthNetworks = false; @@ -58,6 +60,12 @@ setCheckResolvableEhlo(configuration.getValueAsBoolean(false)); } + Configuration config = handlerConfiguration.getChild( + "checkReverseEqualsEhlo", false); + if (config != null) { + setCheckReverseEqualsEhlo(config.getValueAsBoolean(false)); + } + Configuration configRelay = handlerConfiguration.getChild("checkAuthNetworks",false); if(configRelay != null) { setCheckAuthNetworks(configRelay.getValueAsBoolean(false)); @@ -81,10 +89,21 @@ } /** - * Set to true if AuthNetworks should be included in the EHLO check + * Set to true to enable check for reverse equal EHLO * - * @param checkAuthNetworks Set to true to enable + * @param checkReverseEqualsEhlo + * Set to true for enable check */ + public void setCheckReverseEqualsEhlo(boolean checkReverseEqualsEhlo) { + this.checkReverseEqualsEhlo = checkReverseEqualsEhlo; + } + + /** + * Set to true if AuthNetworks should be included in the EHLO check + * + * @param checkAuthNetworks + * Set to true to enable + */ public void setCheckAuthNetworks(boolean checkAuthNetworks) { this.checkAuthNetworks = checkAuthNetworks; } @@ -120,21 +139,48 @@ StringBuffer responseBuffer = session.getResponseBuffer(); boolean badEhlo = false; - // check for resolvable EHLO if its set in config - if (checkResolvableEhlo) { - - /** - * don't check if the ip address is allowed to relay. Only check if it is set in the config. ed. - */ - if (!session.isRelayingAllowed() || checkAuthNetworks) { - - + /** + * don't check if the ip address is allowed to relay. Only check if it + * is set in the config. ed. + */ + if (!session.isRelayingAllowed() || checkAuthNetworks) { + // check for resolvable EHLO if its set in config + if (checkResolvableEhlo) { // try to resolv the provided helo. If it can not resolved do not accept it. try { dnsServer.getByName(argument); } catch (UnknownHostException e) { badEhlo = true; responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Provided EHLO " + argument + " can not resolved"; + session.writeResponse(responseString); + getLogger().info(responseString); + } + } else if (checkReverseEqualsEhlo) { + try { + // get reverse entry + String reverse = dnsServer.getByName( + session.getRemoteIPAddress()).getHostName(); + + if (!argument.equals(reverse)) { + badEhlo = true; + responseString = "501 " + + DSNStatus.getStatus(DSNStatus.PERMANENT, + DSNStatus.DELIVERY_INVALID_ARG) + + " Provided EHLO " + argument + + " not equal reverse of " + + session.getRemoteIPAddress(); + + session.writeResponse(responseString); + getLogger().info(responseString); + } + } catch (UnknownHostException e) { + badEhlo = true; + responseString = "501 " + + DSNStatus.getStatus(DSNStatus.PERMANENT, + DSNStatus.DELIVERY_INVALID_ARG) + + " Ipaddress " + session.getRemoteIPAddress() + + " can not resolved"; + session.writeResponse(responseString); getLogger().info(responseString); } Modified: james/server/trunk/src/java/org/apache/james/smtpserver/HeloCmdHandler.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/smtpserver/HeloCmdHandler.java?rev=407822&r1=407821&r2=407822&view=diff ============================================================================== --- james/server/trunk/src/java/org/apache/james/smtpserver/HeloCmdHandler.java (original) +++ james/server/trunk/src/java/org/apache/james/smtpserver/HeloCmdHandler.java Fri May 19 08:17:40 2006 @@ -27,6 +27,7 @@ import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.james.services.DNSServer; +import org.apache.james.util.mail.dsn.DSNStatus; /** @@ -44,6 +45,8 @@ */ private boolean checkResolvableHelo = false; + private boolean checkReverseEqualsHelo = false; + private boolean checkAuthNetworks = false; private DNSServer dnsServer = null; @@ -56,6 +59,12 @@ if(configuration != null) { setCheckResolvableHelo(configuration.getValueAsBoolean(false)); } + + Configuration config = handlerConfiguration.getChild( + "checkReverseEqualsHelo", false); + if (config != null) { + setCheckReverseEqualsHelo(config.getValueAsBoolean(false)); + } Configuration configRelay = handlerConfiguration.getChild("checkAuthNetworks",false); if(configRelay != null) { @@ -81,6 +90,16 @@ } /** + * Set to true to enable check for reverse equal HELO + * + * @param checkReverseEqualsHelo + * Set to true for enable check + */ + public void setCheckReverseEqualsHelo(boolean checkReverseEqualsHelo) { + this.checkReverseEqualsHelo = checkReverseEqualsHelo; + } + + /** * Set to true if AuthNetworks should be included in the EHLO check * * @param checkAuthNetworks Set to true to enable @@ -97,9 +116,7 @@ public void setDnsServer(DNSServer dnsServer) { this.dnsServer = dnsServer; } - - - + /* * process HELO command * @@ -121,14 +138,14 @@ String responseString = null; boolean badHelo = false; - - // check for resolvable HELO if its set in config - if (checkResolvableHelo) { + /** + * don't check if the ip address is allowed to relay. Only check if it is set in the config. ed. + */ + if (!session.isRelayingAllowed() || checkAuthNetworks) { + + // check for resolvable HELO if its set in config + if (checkResolvableHelo) { - /** - * don't check if the ip address is allowed to relay. Only check if it is set in the config. ed. - */ - if (!session.isRelayingAllowed() || checkAuthNetworks) { // try to resolv the provided helo. If it can not resolved do not accept it. try { @@ -140,6 +157,35 @@ getLogger().info(responseString); } + } else if (checkReverseEqualsHelo) { + try { + // get reverse entry + String reverse = dnsServer.getByName( + session.getRemoteIPAddress()).getHostName(); + + if (!argument.equals(reverse)) { + badHelo = true; + responseString = "501 " + + DSNStatus.getStatus(DSNStatus.PERMANENT, + DSNStatus.DELIVERY_INVALID_ARG) + + " Provided HELO " + argument + + " not equal reverse of " + + session.getRemoteIPAddress(); + + session.writeResponse(responseString); + getLogger().info(responseString); + } + } catch (UnknownHostException e) { + badHelo = true; + responseString = "501 " + + DSNStatus.getStatus(DSNStatus.PERMANENT, + DSNStatus.DELIVERY_INVALID_ARG) + + " Ipaddress " + session.getRemoteIPAddress() + + " can not resolved"; + + session.writeResponse(responseString); + getLogger().info(responseString); + } } } Modified: james/server/trunk/src/test/org/apache/james/smtpserver/SMTPServerTest.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/test/org/apache/james/smtpserver/SMTPServerTest.java?rev=407822&r1=407821&r2=407822&view=diff ============================================================================== --- james/server/trunk/src/test/org/apache/james/smtpserver/SMTPServerTest.java (original) +++ james/server/trunk/src/test/org/apache/james/smtpserver/SMTPServerTest.java Fri May 19 08:17:40 2006 @@ -149,6 +149,8 @@ public InetAddress getByName(String host) throws UnknownHostException { + if ("127.0.0.1".equals(host)) return InetAddress.getByName("james.apache.org"); + return InetAddress.getByName(host); // throw new UnsupportedOperationException("getByName not implemented in mock for host: "+host); } @@ -374,6 +376,35 @@ smtpProtocol1.quit(); } + public void testReverseEqualsHelo() throws Exception { + m_testConfiguration.setReverseEqualsHelo(); + m_testConfiguration.setAuthorizedAddresses("192.168.0.1"); + finishSetUp(m_testConfiguration); + + SMTPClient smtpProtocol1 = new SMTPClient(); + smtpProtocol1.connect("127.0.0.1", m_smtpListenerPort); + + assertTrue("first connection taken", smtpProtocol1.isConnected()); + + // no message there, yet + assertNull("no mail received by mail server", m_mailServer + .getLastMail()); + + String helo1 = "abgsfe3rsf.de"; + String helo2 = "james.apache.org"; + + smtpProtocol1.sendCommand("helo", helo1); + // this should give a 501 code cause the helo not equal reverse of ip + assertEquals("expected error: helo not equals reverse of ip", 501, + smtpProtocol1.getReplyCode()); + + smtpProtocol1.sendCommand("helo", helo2); + // helo is resolvable. so this should give a 250 code + assertEquals("Helo accepted", 250, smtpProtocol1.getReplyCode()); + + smtpProtocol1.quit(); + } + public void testSenderDomainResolv() throws Exception { m_testConfiguration.setSenderDomainResolv(); m_testConfiguration.setAuthorizedAddresses("192.168.0.1/32"); @@ -590,6 +621,35 @@ // this should give a 501 code cause the ehlo could not resolved assertEquals("expected error: ehlo could not resolved", 501, smtpProtocol1.getReplyCode()); + smtpProtocol1.sendCommand("ehlo", ehlo2); + // ehlo is resolvable. so this should give a 250 code + assertEquals("ehlo accepted", 250, smtpProtocol1.getReplyCode()); + + smtpProtocol1.quit(); + } + + public void testReverseEqualsEhlo() throws Exception { + m_testConfiguration.setReverseEqualsEhlo(); + m_testConfiguration.setAuthorizedAddresses("192.168.0.1"); + finishSetUp(m_testConfiguration); + + SMTPClient smtpProtocol1 = new SMTPClient(); + smtpProtocol1.connect("127.0.0.1", m_smtpListenerPort); + + assertTrue("first connection taken", smtpProtocol1.isConnected()); + + // no message there, yet + assertNull("no mail received by mail server", m_mailServer + .getLastMail()); + + String ehlo1 = "abgsfe3rsf.de"; + String ehlo2 = "james.apache.org"; + + smtpProtocol1.sendCommand("ehlo", ehlo1); + // this should give a 501 code cause the ehlo not equals reverse of ip + assertEquals("expected error: ehlo not equals reverse of ip", 501, + smtpProtocol1.getReplyCode()); + smtpProtocol1.sendCommand("ehlo", ehlo2); // ehlo is resolvable. so this should give a 250 code assertEquals("ehlo accepted", 250, smtpProtocol1.getReplyCode()); Modified: james/server/trunk/src/test/org/apache/james/smtpserver/SMTPTestConfiguration.java URL: http://svn.apache.org/viewvc/james/server/trunk/src/test/org/apache/james/smtpserver/SMTPTestConfiguration.java?rev=407822&r1=407821&r2=407822&view=diff ============================================================================== --- james/server/trunk/src/test/org/apache/james/smtpserver/SMTPTestConfiguration.java (original) +++ james/server/trunk/src/test/org/apache/james/smtpserver/SMTPTestConfiguration.java Fri May 19 08:17:40 2006 @@ -37,6 +37,8 @@ private boolean m_checkAuthNetworks = false; private boolean m_checkAuthClients = false; private boolean m_heloEhloEnforcement = true; + private boolean m_reverseEqualsHelo = false; + private boolean m_reverseEqualsEhlo = false; private int m_maxRcpt = 0; @@ -95,6 +97,14 @@ m_ehloResolv = true; } + public void setReverseEqualsHelo() { + m_reverseEqualsHelo = true; + } + + public void setReverseEqualsEhlo() { + m_reverseEqualsEhlo = true; + } + public void setSenderDomainResolv() { m_senderDomainResolv = true; } @@ -137,9 +147,11 @@ if (cmd != null) { if ("HELO".equals(cmd)) { ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkResolvableHelo",m_heloResolv+"")); + ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkReverseEqualsHelo",m_reverseEqualsHelo+"")); ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkAuthNetworks",m_checkAuthNetworks+"")); } else if ("EHLO".equals(cmd)) { ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkResolvableEhlo",m_ehloResolv+"")); + ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkReverseEqualsEhlo",m_reverseEqualsEhlo+"")); ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkAuthNetworks",m_checkAuthNetworks+"")); } else if ("MAIL".equals(cmd)) { ((DefaultConfiguration) heloConfig[i]).addChild(Util.getValuedConfiguration("checkValidSenderDomain",m_senderDomainResolv+"")); --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]