Become a Columnist Microsoft Exchange Site Microsoft Support SiteMSDN Exchange Site

   

Subscribe to OutlookExchange
Anderson Patricio
Ann Mc Donough
Bob Spurzem
Brian Veal
Catherine Creary
Cherry Beado
Colin Janssen
Collins Timothy Mutesaria
Drew Nicholson
Fred Volking
Glen Scales
Goran Husman
Guy Thomas
Henrik Walther
Jason Sherry
Jayme Bowers
John Young
Joyce Tang
Justin Braun
Konstantin Zheludev
Kristina Waters
Kuang Zhang
Mahmoud Magdy
Martin Tuip
Michael Dong
Michele Deo
Mitch Tulloch
Nicolas Blank
Pavel Nagaev
Ragnar Harper
Ricardo Silva
Richard Wakeman
Russ Iuliano
Santhosh Hanumanthappa
Steve Bryant
Steve Craig
Todd Walker
Tracey J. Rosenblath
 
   

Building a List of Spam Hosts

Page 1 | Page 2 | Page 3 | Page 4 | Page 5

Reading in message headers from all items in a folder

To get the IP address of the sending host from e-mail items we have to bind to a folder that contains the e-mails and then parse the message header field to extract the IP address in question.

Bind to the target folder

Below I have set a constant that will contain the folder we are going to bind to.  This can either be a folder in your Inbox or a public folder, like "Public Folders\All Public Folders\System Mail\Spam."  The next line calls the custom GetFolder function with the path of the target folder.  This function will return the last folder in the path as an object.

In GetFolder we first need to bind to the Outlook to be able to retrieve data from it.  With the objOutlook object we then make a MAPI using the Folders method to bind to the first folder in the path.  After that we call the custom GetField function to return the first part of the folder path, everything to the left of the first ?\?.  This function will be covered later underSupporting functions and subs.  With the remaining data, which is returned in the ExtraData variable we start a While statement that will continue to bind to each subfolder until it reaches the last folder.  When the last folder is reached GetField will return a blank ExtraData value which will cause the while statement to exit.  The last line then sets the function to the last folder that was bound to, which is returned to objSPAMFolder.

Const TargetFolder = "Mailbox - Jason Sherry\Inbox\Quarantine: Junk"

Set objSPAMFolder = GetFolder (TargetFolder)

Function GetFolder (FolderPath)
  Set objOutlook = CreateObject("Outlook.Application")
  Set objCurrentFolder = objOutlook.GetNameSpace("MAPI").Folders(GetField (FolderPath,"\"))
  FolderPath = ExtraData
  While FolderPath <> ""
    CurrentFolder = GetField (FolderPath,"\")
    Set objCurrentFolder = objCurrentFolder.Folders(CurrentFolder)
    FolderPath = ExtraData
  Wend
  Set GetFolder = objCurrentFolder
End Function

 

Getting at the message header

Now that we have bound to the folder that contains the mail items we want to process we now need to extract the IP address of the sending server from each mail item.  For this we are going to have to use CDO since you can not get at the message header field with the standard message object.

 In the first two lines we get the EntryID and StoreID, see Working with EntryIDs and StoreIDs for more information, of the folder that contains the messages.  We then create a MAPI session and logon to it with the Logon method.  The code below logins to the default profile you have setup in Outlook.  If you already have Outlook open the current profile will be used, so you must have Outlook installed on the system you are running this script on.  Once we have logged on we then bind to folder using the CDO .GetFolder method by passing it the FolderID and StoreID we set earlier.  After that we start a loop that will iterate through each item in the folder.

 As we go through the loop we get the current message and bind to the Field collection in that message.  From that collection we retrieve the message header from the &H7D001E, PR_TRANSPORT_MESSAGE_HEADERS,field with is stored in the Item property, PR_TRANSPORT_MESSAGE_HEADERS is one of the many message properties.  Now that we have the message header we call the custom GetHostInfo function to parse the header and carry out some checks on the sending host IP.  GetHostInfo will return several fields separated by the tab character, Chr(9), that will be used when we create the contact.  The data returned from GetHostInfo is then saved to HostInfo.  In addition, GetHostInfo sets the sn variable, which will be used later for the last name of the contact.  After GetHostInfo we get the IP address that will be used to create the contact and DNS address on the sending host from HostInfo by parsing it with the GetField function.  Next we save the reminding field, contained in ExtraData, to SpamHostDNS.  After we get the host DNS we parse the message header to retrieve the real IP address of the sending host, which will be saved to the displayName of the contact.  Last the CreateContact sub is called.

 This sub will create a contact when called with the following information: OU for the contact to be created in, cn name of the contact, displayName, description, info (displayed as notes in ADU&C on the Telephone tab), giveName (First Name), and finally sn (Last Name).  This will allow you look at the contacts in the AD and see the IP address that send the spam, the message header of the spam, and if the contact was created based on an input from a file or messages in a folder.  When we look at the GetHostInfo function we will see where many of these properties are set.

Sub ReadInItems (TargetFolder,objSpamContactsOU)

  FolderID = objSPAMFolder.EntryID
  StoreID = objSPAMFolder.StoreID

  Set objSession = CreateObject("MAPI.Session")
  objSession.Logon , , False, False
  Set objCDOFolder = objSession.GetFolder(FolderID, StoreID)
  Set objMessages = objCDOFolder.Messages
  For I = 1 To objMessages.Count
    Set objItem = objMessages.Item(I)
    Set objFields = objItem.Fields
    Set objField = objFields.Item(&H7D001E)
    msgHeader = objField.Value
    HostInfo = GetHostInfo (msgHeader,sn)
    If HostInfo <> "" Then
      IPToBlock = LCase(GetField(HostInfo,Chr(9)))
      SpamHostDNS = ExtraData
      StartIP = InStr(msgHeader,"[")+1
      EndIP =  InStr(msgHeader,"]")
      RealIP = Mid(msgHeader,StartIP,EndIP-StartIP)
      CreateContact (objSpamContactsOU,IPToBlock,RealIP,SpamHostDNS,msgHeader,"Folder",sn)
    End If
  Next
End Sub

Verifying the Host is a Spamer

Since valid messages might get marked as spam and turn up in the folder or input file we need to double check that we aren?t blocking a valid ISP, like earthlink.com.  After we get the IP and the claimed DNS name of the sending host we then call the custom BlackListed function which returns True if the IP checked has been blacklisted by one of the public domain servers.  If the host isn?t blacklisted we then check to see if we can do a reverse DNS lookup on the IP address with the custom NSLookUp function.

With the DNS name returned from NSLookUp, if any, the CheckDomainName function is called.  This function checks to see if the sending host is dynamic, like 123-45-67-89.dial-up.net, and if so removes the dynamic part, which would result in dial-up.net.  It also checks to see if the DNS name is a known host, like earthlink.com.  If it is a known dynamic host the class C address is set to be blocked by CheckDomainName.  If the sending host is a known valid host and not dynamic no data is returned by CheckDomainName, which prevents the contact from being created later.  The CheckDomainName function will be covered later under Supporting functions and subs.  After we call CheckDomainName and the returned value has been saved to HostDNS, we check to see if it contains ?Unknown?,  this would be the case when a host is not found in the valid domain list.  If it does we then append the claimed host name after this value.

After all the checks have been done and the fields have been set for the contact we check to see if the contact should be created based on the class C address of the host by checking if the UserClassC const is set to True.  If it is then ServerIP is changed to the class C addressby calling the GetClassC function.

Last we set GetHostInfo to contain the ServerIP that should be blocked the HostDNS information.

In this function and in CheckDomainName the variables that used to save data to fields in the contact are set.  In the function below HostDNS is used for the description and sn is last name of the new contact.

Function GetHostInfo (MsgHeader,sn)
  StartIP = InStr(MsgHeader,"[")+1
  EndIP =  InStr(MsgHeader,"]")
  ? Gets the sending server IP from the message header
  ServerIP = Mid(MsgHeader,StartIP,EndIP-StartIP)
  ? Saves the real IP address to another variable since ServerIP will be modified later
    RealServerIP = ServerIP
  StartDNS1 = InStr(MsgHeader," from ")+Len(" from ")
  EndDNS1 = InStr(MsgHeader,"(")-1

  ? Gets the sending DNS host name from the header, which can be spoofed
  ClaimedHostDNS = Mid(MsgHeader,StartDNS1,EndDNS1-StartDNS1)

  ? Calls BlackListed function to check if IP has been blacklisted as an open relay or spamer
  If BlackListed (RealServerIP,BlackListedBy) Then

    ? Sets variable that will be saved in the new contact later
    HostDNS = "Blacklisted by [" & BlackListedBy & "] Claimed: " & ClaimedHostDNS
    sn = "Blacklisted"

  Else ? Calls NSLooup function, which retrieves the DNS name for the IP
    RealDNS = NSLookUp (RealServerIP,"Name:")
    If RealDNS <> "Invalid" Then

      ? Calls CheckDomainName to return the non-dymaic part of the domain, if it isn?t a
      ' know valid domain
      HostDNS = CheckDomainName (RealServerIP,ServerIP,RealDNS,sn)
      If InStr(HostDNS,"Unknown ") > 0 Then
        HostDNS = HostDNS & " , claimed: " & ClaimedHostDNS
      End If

    Else ? If the RealDNS name is invalid
      HostDNS = "Failed NSLookup, claimed: " & ClaimedHostDNS
      sn = "Failed NSLookup"

    End If
  End If ? Is Blacklisted
  If UseClassC Then
    ServerIP = GetClassC(ServerIP)
  End If
  GetHostInfo = ServerIP & Chr(9) & HostDNS

End Function

Building a List of Spam Hosts

Page 1 | Page 2 | Page 3 | Page 4 | Page 5

Disclaimer: Your use of the information contained in these pages is at your sole risk. All information on these pages is provided "as is", without any warranty, whether express or implied, of its accuracy, completeness, fitness for a particular purpose, title or non-infringement, and none of the third-party products or information mentioned in the work are authored, recommended, supported or guaranteed by Stephen Bryant or Pro Exchange. OutlookExchange.Com, Stephen Bryant and Pro Exchange shall not be liable for any damages you may sustain by using this information, whether direct, indirect, special, incidental or consequential, even if it has been advised of the possibility of such damages.

Copyright Stephen Bryant 2008