Sunday, February 28, 2010

Automatic archiving of IMAP mailbox

I was looking for a way to let my IMAP server automatically move old mail to the correct IMAP folder based on a given specification. I wanted to simply drag mail that I wanted archived to a IMAP folder called Archives, and then let the server put it in the correct subfolder itself. Inspired by http://wiki.dovecot.org/HowTo/RefilterMail , I wrote this Python script:
  1. #!/usr/bin/python  
  2. import imaplib, re, os  
  3.   
  4. server = imaplib.IMAP4('localhost')  
  5. server.login('username''password')  
  6. r = server.select('Archives')  
  7. resp, items = server.search(None'ALL')  
  8.   
  9. for m in items[0].split():  
  10.         resp, data = server.fetch(m, '(BODY[HEADER.FIELDS (SUBJECT FROM TO)])')  
  11.         _, headers = data[0]  
  12.   
  13.         dst = None  
  14.         if re.search('To: .*@student.dtu.dk', headers): dst = 'Archives.2010.DTU'  
  15.         if re.search('Subject: .*\[somelist\]', headers): dst = 'Archives.2010.Somelist'  
  16.         if dst == None: dst = 'Archives.2010'  
  17.   
  18.         resp, data = server.copy(m, dst)  
  19.         if resp == 'OK':  
  20.                 server.store(m, '+Flags''\\Deleted')  
  21.   
  22. server.expunge()  
You can obscure the password by using base64.b64decode to prevent people seeing you password when looking over your shoulder.

To make the script run automatically every time a mail is dropped to the Archives folder, use incron. Type incrontab -e and write the following line
/home/username/Maildir/.Archives/cur/ IN_MOVED_TO,IN_ONESHOT python /path/to/script
Where /path/to/script here is the path of the above Python script.

Also, if you want to use this automatic triggering, add the following line to the end of the Python script
os.system('incrontab --reload')

Friday, January 22, 2010

Rogue DHCP detector in Nagios

This Python script I created can be used with Nagios to warn if there are unauthorized DHCP servers on the network. No third party libraries are used.

At the moment the script only checks at IP level, and does not return the MAC address of the rogue server. My plan is to expand this at some stage, but at the moment we do not really need this in our setup.

  1. #!/usr/bin/python  
  2. from socket import *  
  3. from binascii import *  
  4. from random import *  
  5. from struct import *  
  6.   
  7. # local machine mac address  
  8. chaddr = unhexlify('001122334455')  
  9.   
  10. # allowed dhcp servers  
  11. whitelist = set(['11.22.33.44'])  
  12.   
  13. # random session id (xid)  
  14. xid = pack('L', randrange(02**32 - 1 ))  
  15.   
  16. # setup socket  
  17. s = socket(AF_INET, SOCK_DGRAM)  
  18. s.bind(('0.0.0.0'68))  
  19. s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)  
  20.   
  21. request = \  
  22.     '\x01\x01\x06\x00' \  
  23.     + xid \  
  24.     + ''.ljust(20'\x00') \  
  25.     + chaddr.ljust(16'\x00') \  
  26.     + ''.ljust(192'\x00') \  
  27.     + '\x63\x82\x53\x63' \  
  28.     + '\x35\x01\x03' \  
  29.     + '\xff'  
  30. s.sendto(request, ('255.255.255.255'67))  
  31.   
  32. # listen for dhcp packets for max 2.5 seconds  
  33. status = "OK - No rogue dhcp servers detected"  
  34. r = 0  
  35. s.settimeout(2.5)  
  36. while 1:  
  37.     try:  
  38.         buf, (ip, port) = s.recvfrom(65565)  
  39.     except:  
  40.         break  
  41.     opcode, = unpack_from('B', buf)  
  42.     if not (ip in whitelist and opcode == 0x02):  
  43.         r = 2  
  44.         status = "CRITICAL - Rogue dhcp server detected on IP-addr: " + ip  
  45.         break  
  46.   
  47. s.close()  
  48. print status  
  49. exit(r)