# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2005 Business Management Systems, Inc.
# This code is under the GNU General Public License.  See COPYING for details.

# Heuristically determine whether a domain name is for a dynamic IP.

# examples we don't yet recognize:
#
# wiley-268-8196.roadrunner.nf.net at ('205.251.174.46', 4810)
# cbl-sd-02-79.aster.com.do at ('200.88.62.79', 4153)

import re

ip3 = re.compile('[0-9]{1,3}')
hpats = (
 'h[0-9a-f]{12}[.]',
 'h\d*n\d*c\d*o\d*\.',
 'pcp\d{6,10}pcs[.]',
 'no-reverse',
 'S[0-9a-f]{16}[.][a-z]{2}[.]',
 'user<3>\.',
 '[Cc]ust<3>\.',
 '^<3>\.',
 'ppp[^.]*<3>\.',
 '-ppp\d*\.',
 '\d*-<3>\.',
 '[0-9a-f]{1,3}-<3>\.',
 'p<3>\.pool',
 'h<3>\.',
 'xdsl-\d*\.',
 '-\d*-\d*\.',
 '\.adsl\.',
 '\.cable\.'
)
rehmac = re.compile('|'.join(hpats))

def is_dynip(host,addr):
  """Return True if hostname is for a dynamic ip.
  Examples:

  >>> is_dynip('post3.fabulousdealz.com','69.60.99.112')
  False
  >>> is_dynip('adsl-69-208-201-177.dsl.emhril.ameritech.net','69.208.201.177')
  True
  >>> is_dynip('[1.2.3.4]','1.2.3.4')
  True
  >>> is_dynip('c-71-63-151-151.hsd1.mn.comcast.net','71.63.151.151')
  True
  """
  if host.startswith('[') and host.endswith(']'):
    return True                                 # no ptr
  if addr:
    if host.find(addr) >= 0: return True
    if addr.find(':') >= 0: return False        # IP6
    a = addr.split('.')
    ia = map(int,a)
    h = host
    m = ip3.findall(host)
    if m:
      g = map(int,m)[:4]
      ia3 = (ia[1:],ia[:3])
      if g[-3:] in ia3: return True
      if g[0] == ia[3] and g[1:3] == ia[:2]: return True
      if g[-2:] == ia[2:]: return True
      g.reverse()
      if g[:3] in ia3: return True
      if g[:2] == ia[2:]: return True
      if ia[2:] in (g[:2],g[-2:]): return True
      for m in ip3.finditer(host):
        if int(m.group()) == ia[3]:
          h = host[:m.start()] + '<3>' + host[m.end():]
          break
    if rehmac.search(h): return True
    if host.find(''.join(a[:3])) >= 0: return True
    if host.find(''.join(a[1:])) >= 0: return True
    x = "%02x%02x%02x%02x" % tuple(ia)
    if host.lower().find(x) >= 0: return True
  return False

if __name__ == '__main__':
  import fileinput
  import sets
  seen = sets.Set()
  for ln in fileinput.input():
    a = ln.split()
    if a[3:5] == ['connect','from']:
      host = a[5]
      if host.startswith('[') and host.endswith(']'):
        continue	# no PTR
      ip = a[7][2:-2]
      if ip in seen: continue
      seen.add(ip)
      if is_dynip(host,ip):
        print '%s\t%s DYN' % (ip,host)
      else:
        print '%s\t%s' % (ip,host)
