mimeutils.java
来自「spam source codejasen-0.9jASEN - java An」· Java 代码 · 共 739 行 · 第 1/2 页
JAVA
739 行
/*
* @(#)MimeUtils.java 31/10/2004
*
* Copyright (c) 2004, 2005 jASEN.org
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* 3. The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. Any modification or additions to the software must be contributed back
* to the project.
*
* 5. Any investigation or reverse engineering of source code or binary to
* enable emails to bypass the filters, and hence inflict spam and or viruses
* onto users who use or do not use jASEN could subject the perpetrator to
* criminal and or civil liability.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JASEN.ORG,
* OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.jasen.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import javax.mail.Address;
import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.AddressException;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.ParseException;
import org.jasen.error.DNSException;
import org.jasen.error.ErrorHandlerBroker;
import org.jasen.error.JasenParseException;
import org.jasen.error.ParseErrorType;
import org.jasen.interfaces.DNSResolver;
import org.jasen.interfaces.InetAddressResolver;
import org.jasen.interfaces.ReceivedHeaderParser;
import org.jasen.interfaces.ReceivedHeaderParserData;
import org.jasen.io.ByteToCharUTF7Converter;
import org.jasen.net.MXRecord;
/**
* <P>
* General Mime utilities.
* </P>
* @author Jason Polites
*/
public class MimeUtils
{
/**
* Undetermined (test not yet performed)
*/
public static final int FORGERY_UNDETERMINED = -1;
/**
* Confirmed forgery
*/
public static final int FORGERY_CONFIRMED = 1;
/**
* Confirmed authentic
*/
public static final int FORGERY_REJECTED = 0;
/**
* Forgery status could not be determined with absolute certainty
*/
public static final int FORGERY_UNKNOWN = 2;
public static String[] ATTACHMENT_DISPOSITIONS = {MimeMessage.ATTACHMENT, MimeMessage.INLINE};
public static Header[] getAllHeaders(MimeMessage message) throws MessagingException {
Header[] headers = null;
Enumeration e = message.getAllHeaders();
// We have to use a Vector here because we can't get the size
Vector vHeaders = new Vector();
while (e.hasMoreElements()) {
vHeaders.add(e.nextElement());
headers = (Header[]) vHeaders.toArray(new Header[vHeaders.size()]);
}
return headers;
}
public static boolean isValidAddress(String address) {
String regex = "^[a-zA-Z][\\w\\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\\w\\.-]*[a-zA-Z0-9]\\.[a-zA-Z][a-zA-Z\\.]*[a-zA-Z]$";
return address.matches(regex);
}
/**
* Verifies the given sender address against the information in the last (most recent) received header line
* <BR><BR>
* Specifically, this does the following:
* <BR><BR>
* get domain of sender<BR>
* get IP address of last (most recent) MTA<BR>
* get hostname of last (most recent) MTA<BR>
* if (MTA IP Address resolves to MTA hostname) then<BR>
* use MTA hostname for MX IP records<BR>
* else<BR>
* use MTA IP Address<BR>
*
* get MX records for sender domain<BR>
* if(at least 1 MX record IP matches MTA IP) then valid<BR>
*
* @param parser The parser to use on the header line
* @param receivedHeaderLine The last (most recent) received header line
* @param senderAddress The From address (NOT the envelope address)
* @return True if the sender is valid, false otherwise
* @throws JasenParseException
* @throws UnknownHostException
* @throws DNSException
*/
public static boolean verifySenderAddress(DNSResolver dresolver, InetAddressResolver iresolver, ReceivedHeaderParser parser, String receivedHeaderLine, String senderAddress) throws JasenParseException, UnknownHostException, DNSException {
ReceivedHeaderParserData data = parser.parse(receivedHeaderLine, iresolver);
if(data == null) {
throw new JasenParseException("Unable to parse header.", ParseErrorType.PARSE_ERROR);
}
// Use the InetAddress cache
InetAddress receiverAddress = iresolver.getByName(data.getSenderIPAddress());
String senderDomain = getDomainFromAddress(senderAddress);
String receiverDomain = receiverAddress.getHostName();
// Get the MX records for the sender domain
MXRecord[] senderMXRecords = DNSUtils.getMXRecords(dresolver, senderDomain);
if (senderMXRecords != null && senderMXRecords.length > 0) {
// Get the root domain for both the receiver and sender
if (!DNSUtils.isIPv4Address(receiverDomain)) {
String senderRootDomain = DNSUtils.getRootDomain(data.getSenderHostName());
String receiverRootDomain = DNSUtils.getRootDomain(receiverDomain);
if (receiverRootDomain.equalsIgnoreCase(senderRootDomain)) {
// Get the MX records for the receiver domain
MXRecord[] receiverMXRecords = DNSUtils.getMXRecords(dresolver, receiverRootDomain);
// The sender address is valid if one IP matches
MXRecord senderMX = null;
MXRecord receiverMX = null;
if (senderMXRecords != null && senderMXRecords.length > 0) {
if (receiverMXRecords != null && receiverMXRecords.length > 0) {
for (int i = 0; i < senderMXRecords.length; i++) {
senderMX = senderMXRecords[i];
for (int j = 0; j < receiverMXRecords.length; j++) {
receiverMX = receiverMXRecords[j];
if (senderMX.getAddress().getHostAddress().equalsIgnoreCase(receiverMX.getAddress().getHostAddress())) {
return true;
}
}
}
}
else {
return false;
}
}
else {
return false;
}
}
else {
// The IP does not match the host. This may be a forgery but we will still test the MX
// records against the IP address
String mtaIPAddress = data.getSenderIPAddress();
for (int i = 0; i < senderMXRecords.length; i++) {
if (senderMXRecords[i].getAddress().getHostAddress().equals(mtaIPAddress)) {
return true;
}
}
}
}
else {
// We could not resolve the receiver IP address to a domain
return false;
}
}
else {
// No valid MX record for this sender
return false;
}
return false;
}
/**
* Converts an Address object to an Internet Address with strict address parsing
* @param address
* @return The parsed InternetAddress
* @throws AddressException
*/
public static InternetAddress toInternetAddress(Address address) throws AddressException {
return toInternetAddress(address, true);
}
/**
* Converts an Address object to an Internet Address
* @param address
* @param strict If true, address parsing is strict
* @return The parsed InternetAddress
* @throws AddressException
*/
public static InternetAddress toInternetAddress(Address address, boolean strict) throws AddressException {
if (address instanceof InternetAddress) {
return (InternetAddress) address;
}
else {
return InternetAddress.parse(address.toString(), strict)[0];
}
}
/**
* Determines if the loaded message is a forgery.
* <br/>
* This is done by looking at the last (most recent) received header and determining if the hostname of
* the sending server matches the hostname provided by the header information via the DNS
* @param resolver The resolver used to resolve InetAddresses
* @param message The MimeMessage to test
* @param senderAddress The envelope sender
* @param parser The parser to use to parse the "Received" header(s)
* @return An integer representing the determination. 0 = Not a forgery, 1 = Definately a forgery, 2 = Unsure or could not be determined
* @throws MessagingException
* @throws CacheException
* @throws JasenParseException
*/
public static int isForgery(InetAddressResolver resolver, MimeMessage message, String senderAddress, ReceivedHeaderParser parser) throws MessagingException, JasenParseException {
// Get the header
String[] headers = message.getHeader("Received");
if(headers != null) {
boolean hostNameIsIP = false;
String header = headers[0];
// Parse the header
ReceivedHeaderParserData data = null;
try {
data = parser.parse(header,resolver);
if(data != null) {
// Get the IPAddress of the sending server
String senderIP = data.getSenderIPAddress();
// Get the reported hostname
String senderHost = data.getSenderHostName();
// If the sender host is an IP address, but not the same as the "actual"
// IP, we have a forgery
hostNameIsIP = DNSUtils.isIPAddress(senderHost);
if(hostNameIsIP) {
if(!senderHost.equals(senderIP)) {
return FORGERY_CONFIRMED; // Forgery
}
}
try
{
// Now, attempt to get the real hostname
String realHost = resolver.getByName(senderIP).getHostName();
// If the host equals the ip, we couldn't resolve
if(realHost.endsWith(senderIP)) {
if(hostNameIsIP) {
// Probably a forgery, but we can't be sure
return FORGERY_UNKNOWN;
}
else
{
// Sender identified a host that does not match the DNS, forgery
return FORGERY_CONFIRMED;
}
}
else
{
// The host was returned, we need to get the "root" of this hostname
String rootRealHost = DNSUtils.getRootDomain(realHost);
// Now get the root of the reported host
String rootReportedHost = DNSUtils.getRootDomain(senderHost);
// If they match, we are ok
if(rootRealHost.equalsIgnoreCase(rootReportedHost)) {
return FORGERY_REJECTED;
}
else
{
// try the domain of the sender
String rootSenderHost = DNSUtils.getRootDomain(getDomainFromAddress(senderAddress));
if(rootRealHost.equalsIgnoreCase(rootSenderHost)) {
return FORGERY_REJECTED; // ok
}
else
{
return FORGERY_CONFIRMED; // forgery
}
}
}
}
catch (UnknownHostException e)
{
// No host.. must be forged
return FORGERY_CONFIRMED;
}
}
else {
// Couldn't parse
return FORGERY_UNKNOWN;
}
}
catch (JasenParseException e) {
// Can't parse the header
return FORGERY_UNKNOWN;
}
}
else
{
// no headers, can't be sure
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?