下载中心 | 网站地图 | 站内搜索 | 加入收藏

安恒公司 / 技术文章 / 安恒公司网管员手记 / 安恒网管员手记: 邮件病毒过滤

2004-06-17 刘世伟  阅:    下页: »
安恒网管员手记: 邮件病毒过滤
#!/usr/local/bin/python --

"""

This is a program by Dru Nelson. You can contact me
and discuss bugs/issues/kudos at dnelson@redwoodsoft.com.

This program acts as a qmail-queue filter. 
If qmail-smtpd receives a piece of email, it normally
sends it to qmail-queue. With a small patch, it can
now send it to this program which will then call 
qmail-queue.

20000513 - DN - Making the initial version: ILOVEYOU
20040621 - liu shiwei V1.3

"""


import os, sys, string, time, traceback, re

Version  = '1.3'
PyVersion  = '1.0'
Logging  = 1
Debug    = 0
QmailD   = 501
LogFile  = None
TestMode = None
Filters  = []
MailEnvelope = ''
MailData     = ''
MaxData = 2000000
MinData = 0
MailLen = 0
ValidActions = {'trap': '', 'drop' : '', 'block' :'','back' :'' }



def openlog():
  global LogFile

  if not Logging:
     return
  try:
    LogFile = os.open('//var/qmail/qmfilt/qm.log', os.O_APPEND|os.O_WRONLY|os.O_CREAT, 0744) 
  except:
    if TestMode:
      print "Can't create /var/log/qmfilt"
    else:
      # Indicate a write error
      sys.exit(53)

def log(message):
  message = time.asctime(time.localtime(time.time())) + " - " + message + "\n"
  if Logging:
    os.write(LogFile, message)
    # Indicate a write error
    #sys.exit(53)
  if TestMode:
    print message


def showFilters():
  
  if len(Filters) == 0:
    print "No filters"
  for f in Filters:
    print "Filter -  %s - Action: %s  Regex: %s" % (f[0], f[1], f[2])

def readFilters():
  global Filters

  try:
    file = open('/var/qmail/control/qmfilt', 'r') 
    configLines = file.readlines()
    file.close()
  except:
    log("Can't read /var/qmail/control/qmfilt")
    if not TestMode:
      # Indicate a 'cannot read config file error'
      sys.exit(53)

  reg = re.compile('(.*)::(.+)::(.+)::(.*)::(.*)::')
  for line in configLines:
    if line[0] == '#':
      continue
    m = reg.match(line)
    if m != None:
      action = string.lower(m.group(2))
      if not ValidActions.has_key(action):
         log("Invalid action in config file [%s] - SKIPPED" %(action))
         continue
      Filters.append( [m.group(1), string.lower(m.group(2)), m.group(3),m.group(4),m.group(5)] )    
def readDescriptor(desc):
  global MailLen
  result = ''
  while 1:
    data = os.read(desc, 16384)
    if (data == ''):
      break 
    result = result + data
  return result

def writeDescriptor(desc, data):
  while data:
    num  = os.write(desc, data)
    data = data[num:]

  os.close(desc)


def filterHits():
  global MailLen
  MailLen=len(MailData)
  for regEx in Filters:
    if Debug==1:   
       log("size-%d,%s:%s,%s" % (MailLen,regEx[0],regEx[3],regEx[4]))
    if (len(regEx[3])>0) and (MailLen < int(regEx[3])):
       if Debug==1:
         log("skip %d<%s" % (MailLen,regEx[3]))
       continue
    if (len(regEx[4])>0) and (MailLen > int(regEx[4])):
       if Debug==1:	    
         log("skip %d>%s" % (MailLen,regEx[4]))
       continue
    if Debug==1:   
       log("run! %s-%s" %( regEx[0],regEx[2]));
    reg = re.compile(regEx[2], re.M|re.I)
    match = reg.search(MailData)
    if match:
      return regEx[1], regEx[0]
  return None,None


def storeInTrap(hit):
  try:
    pid = os.getpid()
    mailFile = os.open('/var/qmail/qmfilt/qmfilt.%s' %(pid), os.O_WRONLY|os.O_CREAT|os.O_EXCL, 0744) 
  except:
    log("Can't create /var/qmail/qmfilt/qmfilt.%s" %(pid))
    # Indicate a write error
    sys.exit(53)

  try:
    (size, inode, size, size, size,size, size, size, size, size) = os.fstat(mailFile)
    os.rename('/var/qmail/qmfilt/qmfilt.%s' %(pid), '/var/qmail/qmfilt/%s.mail' %(inode))
  except:
    log("Can't rename /var/qmail/qmfilt/qmfilt.%s -> /var/qmail/qmfilt/%s.mail" %(pid, inode))
    # Indicate a write error
    sys.exit(53)

  try:
    envFile = os.open('/var/qmail/qmfilt/%s.envelope' %(inode), os.O_WRONLY|os.O_CREAT|os.O_EXCL, 0744) 
    mesgFile = os.open('/var/qmail/qmfilt/%s.qmfilt' %(inode), os.O_WRONLY|os.O_CREAT|os.O_EXCL, 0744) 
    writeDescriptor(mailFile, MailData)
    writeDescriptor(envFile,  MailEnvelope)
    writeDescriptor(mesgFile, "Matched filter [ %s] to file %s" %(hit, inode))
    log("Matched filter [ %s] to file %s" %(hit, inode))
  except:
    log("Can't create/write files into trap")
    # Indicate a write error
    sys.exit(53)

  return 0


def sendToQmailQueue():
  
  # Open a pipe to qmail queue
  fd0 = os.pipe()
  fd1 = os.pipe()
  pid = os.fork()
  if pid < 0:
    log("Error couldn't fork")
    sys.exit(81)
  if pid == 0:
    # This is the child
    os.dup2(fd0[0], 0)
    os.dup2(fd1[0], 1)
    i = 2
    while (i < 64):
      try:
        os.close(i)
      except:
        pass
      i = i + 1
    os.chdir('/var/qmail')
    #time.sleep(10)
    os.execv("bin/qmail-queue", ('bin/qmail-queue',))
    log("Something went wrong")
    sys.exit(127)  # This is only reached on error
  else:
    # This is the parent
    # close the readable descriptors
    os.close(fd0[0])
    os.close(fd1[0])


  # Send the data
  recvHdr = "Received: (anhengmail: V%s); " %(Version)
  recvHdr = recvHdr + time.strftime("%d %b %Y %H:%M:%S", time.gmtime(time.time()))
  recvHdr = recvHdr + " -0000\n"
  os.write(fd0[1], recvHdr)
  writeDescriptor(fd0[1], MailData)
  writeDescriptor(fd1[1], MailEnvelope)

  # Catch the exit code to return 
  result = os.waitpid(pid, 0)[1]
  if PyVersion > '1.5.1':
    if os.WIFEXITED(result):
      return os.WEXITSTATUS(result)
    else:
      log("Didn't exit normally")
      sys.exit(81)
  else:
    return result


def main(argv, stdout, environ):

  global TestMode
  global MailData
  global MailEnvelope
  global PyVersion
  global MaxData
  global MinData
  PyVersion = string.split(sys.version)[0]

  if len(argv) > 1 and argv[1] == '--test':
    TestMode = 1

  os.setuid(QmailD)

  # Insure Environment is OK

  # Try to open log
  openlog()

  if not os.path.exists('/var/qmail/qmfilt'):
    # Indicate a problem with the queue directory
    log("Directory /var/qmail/qmfilt doesn't exist")
    if not TestMode:
      sys.exit(61)

# #Python 1.5.2 feature
#  if not os.access('/var/qmail/qmfilt', os.W_OK):
#    # Indicate a problem with the queue directory
#    log("Directory /var/qmail/qmfilt doesn't have write permission")
#    if not TestMode:
#      sys.exit(61)

  if os.path.exists('/var/qmail/control/qmfilt'):
    readFilters()
  else:
    if TestMode:
      print "No filter file /var/qmail/control/qmfilt - no filters applied"

  if TestMode:
    showFilters()

  # Go no further if in test mode
  if TestMode:
    sys.exit(0)



  # Get the data

  # Read the data
  MailData     = readDescriptor(0)
  MailLen = len(MailData)
  # Read the envelope 
  MailEnvelope = readDescriptor(1)
  if (MailLen==0):
    sys.exit(0)
  if (MailLen>MaxData or MinData>MailLen):	  
	       log(MailEnvelope+"-GO-size:%d" % MailLen)
	       sendToQmailQueue()
               sys.exit(0)
    	  
  if Debug==9:	  
    log(MailData)
  log(MailEnvelope+"-size:%d" % MailLen)

  action,hit = filterHits()

  if action == 'trap':
    storeInTrap(hit)
  if action == 'block':
    log("Matched filter [ %s] and email was BLOCKED/Refused delivery" %(hit))
    sys.exit(31)
  if action == 'back':
    sendToQmailQueue()
    
    storeInTrap(hit)
  if action == 'drop':
    log("Matched filter [ %s] and email was DROPPED" %(hit))
  if action == None:
    sendToQmailQueue()

  if Debug==9:
    log("qmailqueue returned [%d]" %(result))
  sys.exit(0)

if __name__ == "__main__":
  try:
    main(sys.argv, sys.stdout, os.environ)

  # Catch the sys.exit() errors
  except SystemExit, val:
    sys.exit(val)
  except:
    # return a fatal error for the unknown error
    if TestMode:
      traceback.print_exc()
    sys.exit(81)
   
下页: »   

相关文章
btrfs试用 --安恒网管员手记 - 11-01-17 - 阅读: 235285
EtherScope II系列网络通V5版本发布,再次提升网络管理的能力 - 10-11-01 - 阅读: 179057
OptiView III的防病毒能力(OPVS3-GIG,OPVS3-GIG/W,OPVS3-GIG/S,OPVS3-GIG/PSVS) - 10-02-25 - 阅读: 171077
ezmlm邮件列表使用mysql方式管理帐号 - 08-11-20 - 阅读: 143703
NetSecure - NetTool II代在线型网络测试仪新选件-为发现间谍软件、广告插件和病毒提供革命性方式 - 07-09-12 - 阅读: 176252
OptiFiber光纤认证OTDR 新模块-573x试用手记 - 07-07-25 - 阅读: 230964
Visual UpTime Select 2.5增强了网络管理者透视全网VoIP呼叫的各段性能的能力 - 07-06-12 - 阅读: 218397
Drupal-chatroom中文乱码 --安恒网管员手记 - 07-06-05 - 阅读: 222612
网络管理员常见网络故障和错误解决方法-协议分析指南 - 07-04-18 - 阅读: 242895
中小企业网络管理的选择和应用分析 - 07-03-28 - 阅读: 227094
NetFlow技术与高校网络管理 - 07-03-12 - 阅读: 232681
福禄克网络收购Crannog Software增强企业网络管理能力 - 07-01-18 - 阅读: 230730
评测:NetTool SeriesⅡ网络万用表二代试用手记 - 06-12-07 - 阅读: 219539
网络管理产品 - 06-11-29 - 阅读: 17438
在debian下用eaccelerator加速php性能 --安恒网管员手记 - 06-06-28 - 阅读: 283307
利用内存磁盘加速mysql --安恒网管员手记 - 06-06-26 - 阅读: 245510
linux在安恒公司的应用 ---安恒网管员手记 - 06-01-16 - 阅读: 314938
qmail+debian --安恒网管员手记 - 06-01-15 - 阅读: 247272
mysql 4.1+ 汉字乱码问题研究 --安恒网管员手记 - 05-09-15 - 阅读: 300234
debian下应用raid5提高数据安全性--安恒网管员手记 - 05-05-02 - 阅读: 286132
相关产品
OptiView Console 控制台软件(网络管理系统)OVC - 04-04-27 - 阅读: 1156805

Email给朋友 打印本文
版权所有·安恒公司 Copyright © 2004   www.anheng.com.cn   All Rights Reserved    
北京市海淀区首体南路9号 主语国际商务中心4号楼8层 (邮编100048) 电话:010-88018877