Submitted By: Keith Mashinter

Summarizes Microsoft Exchange 2003 appserver.log files by various criteria, including IP address, sender, and recipient.

Visual Basic
Edit|Remove
== ipsummary.cmd == 
@echo off 
rem Run the daily ipsummary.js, noting the logs are in GMT and Toronto is GMT-5hours. 
rem 
rem at 23:31 /every:M,T,W,Th,F,S,Su "G:\ExchSrvr\APPSERVER.run\ipsummary.cmd" 
cd /d "%~dp0" 
set thisdate=%date:~10,4%%date:~4,2%%date:~7,2% 
rem echo %thisdate% 
cscript.exe //nologo ipsummary.js 0<..\APPSERVER.log\%thisdate%.log 1>summary%thisdate%.txt 2>summary%thisdate%.log 

== ipsummary.js == 
// ipsummary.js 
// Summarize email by client-ip [2] and sender-email [19], and ip-sender-recip-subject. 
// This also looks up the country for the client-ip-address. 
// Sites providing GeoIP data by country for free: 
//  http://www.iporigin.org/ 
//  http://software77.net/geoip-software.htm 
//  http://www.maxmind.com/download/geoip/database/ 
//  http://www.ip-to-location.com/ 
// Other tools: 
//  http://www.geoiptool.com/ 
//  http://ws.arin.net/whois/ 
var fsoForReading = 1 
var fsoForWriting = 2 
var fsoForAppending = 8 
var fso = new ActiveXObject("Scripting.FileSystemObject") 
function debug(str) { WScript.StdErr.WriteLine(str) } 
var COUNTRY_RE = new RegExp(":$") 
var IPCOUNTRY = [] 
var IPCOUNTRY_CACHE = {} 
var IP_m0 = 256*256*256, IP_m1 = 256*256, IP_m2 = 256, IP_m3 = 1 
function ip2Int(ipStr) { 
 var ip = ipStr.split(".") 
 return ip[0]*IP_m0+ip[1]*IP_m1+ip[2]*IP_m2+ip[3]*IP_m3 
} 
function loadIPCOUNTRY(file) { 
 var is = fso.OpenTextFile(file, 1, false) 
 var line 
 var nr = 0 
 while (!is.AtEndOfStream) { 
  line = is.ReadLine().split(" ") 
  ip1 = ip2Int(line[1]) 
  ip2 = ip2Int(line[2]) 
  IPCOUNTRY[IPCOUNTRY.length] = [ip1,ip2,line[0].replace(COUNTRY_RE,"")] 
  //debug(IPCOUNTRY[IPCOUNTRY.length-1]); if (nr++ > 1000) break; 
  //if (line[1] === "41.156.0.0") debug(ip1) 
 } 
 is.Close() 
 is = null 
} 
function bisectCountry(ipStr) { 
 var ip = ipStr.split(".") 
 if (ip.length < 4) return "" 
 var ip = ip2Int(ipStr) 
 var found = false, i0 = 0, i1 = 0, i2 = IPCOUNTRY.length-1, d0, d1 
 while (i2-i0 > 1) { 
  i1 = parseInt((i0+i2)/2) 
  d0 = IPCOUNTRY[i1][0] - ip 
  d1 = IPCOUNTRY[i1][1] - ip 
  //if (ipStr === "65.61.203.1") debug(i0+","+i1+","+i2+","+d0+","+d1+" "+ip+","+IPCOUNTRY[i1]) 
  if (d0 <= 0 && d1 >= 0) { found = true; break; } 
  if (d0 > 0) i2 = i1 
  else i0 = i1 
 } 
 return (found) ? IPCOUNTRY[i1][2] : "" 
} 
function secantCountry(ipStr) { 
 // should be faster than bisection but may not converge with non-constant increasing/decreasing curves 
 // initial f(x) and guesses x0, x1 
 // while (x_n - x_(n-1) > tolerance) { 
 //  x_(n+1) = x_n - ( x_n - x_(n-1) ) /( f(x_n) - f(x_(n-1)) ) * f(x_n) 
 //  if (f(x_(n+1)) = 0) return x_(n+1) 
 //  n = n + 1 
 // } 
} 
debug( (new Date()) +" Loading ipcountry lookup table ... ") 
loadIPCOUNTRY("ipcountry-ascii.txt") 
debug( (new Date()) +" Loaded "+ IPCOUNTRY.length +" entries.") 
var ins = WScript.StdIn 
var ous = WScript.StdOut 
var line, ip, ipemail, ipemailrecipsubj, country 
var map = {} 
debug("Counting input by client-ip, sender-email, and ip-sender-recip-subject ...") 
while (!ins.AtEndOfStream) { 
 line = ins.ReadLine().split("\t") 
 if (line.length < 19 || line[0].lastIndexOf("#",0) == 0) continue; 
 ip = line[2] 
 ipemail = ip+"\t"+line[19] 
 ipemailrecipsubj = ipemail+"\t"+line[7]+"\t"+line[18] 
 country = bisectCountry(ip) 
 if (map[ip]) map[ip][0]++ 
 else map[ip] = [1,country,ip] 
 if (map[ipemail]) map[ipemail][0]++ 
 else map[ipemail] = [1,country,ipemail] 
 if (map[ipemailrecipsubj]) map[ipemailrecipsubj][0]++ 
 else map[ipemailrecipsubj] = [1,'',ipemailrecipsubj] 
} 
debug((new Date())+ " Sorting by highest count ...") 
var ary = [] 
for (var key in map) { 
 ary[ary.length] = map[key] 
} 
map = null // release memory for reuse 
function sortDesc(a,b) { return b[0] - a[0] } 
ary.sort(sortDesc) 
debug((new Date())+ " Writing ...") 
ous.WriteLine(["count","country","ip-address","sender","recipient","subject"].join("\t")) 
for (var i=0; i<ary.length; i++) { 
 ous.WriteLine(ary[i].join("\t")) 
} 
ary = null // release memory for reuse 
debug((new Date())+ " Done.")