###############################################################################
#                                                                             #
#   Copyright 2005 University of Cambridge Computer Laboratory.               #
#                                                                             #
#   This file is part of Nprobe.                                              #
#                                                                             #
#   Nprobe is free software; you can redistribute it and/or modify            #
#   it under the terms of the GNU General Public License as published by      #
#   the Free Software Foundation; either version 2 of the License, or         #
#   (at your option) any later version.                                       #
#                                                                             #
#   Nprobe is distributed in the hope that it will be useful,                 #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of            #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             #
#   GNU General Public License for more details.                              #
#                                                                             #
#   You should have received a copy of the GNU General Public License         #
#   along with Nprobe; if not, write to the Free Software                     #
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA #
#                                                                             #
###############################################################################



##############################################################################
## 
##
## Distinguish TCP/HTTP connections of interest based on some HTTP
## characteristic
##
## 

############################################################################ 

import string
import regsub
import sys
from array import *

from nprobe import TCP_SERV_SYN, TCP_CLI_SYN
#import nprobe
#from np_obnode import *
#from  np_longutil import * 

############################################################################

class TFilter:

    def __init__(self):

	self.filters()
	self.counters()

	print 'Tfilter initialised'

############################################################################

    def pss(self, connrec, translist):

	#
	# Present to filters
	#

	for f in self.filters:
	   if not f(connrec, translist):
	    return 0

	return 1 

    

############################################################################

    def filters(self):

	#
	# Construct dictionary of filters
	#
	
	
	
	self.fdict = {}
	

	#
	# Add new filters here
	#
	self.flist = [
	    [0, self.pass_all, 'None (default) '],
	    [1, self.syns_seen, 'SYNs not seen '],
	    [2, self.noloss, 'Rtmts or seq gaps '],
	    [3, self.loss, 'No Rtmts or seq gaps '],
            [4, self.cli_syn_seen, 'Client SYN not seen'],
	    [10, self.pers_and_multi, 'Not persistent with multiple transactions '],
	    [12, self.long_conn, 'Connections < 20 packets '],
	    [50, self.browsing_on_a_Mac, 'Browser host not a Mac '],
	    [51, self.browsing_on_a_MacP, 'Browser host not a Mac Power PC ']
	    ]

	for f in self.flist:
	    self.fdict[f[0]] = (f[1], f[2])
	
	self.nfilt = 51

	#
	# Initialise with 'hard' filters
	#
	#self.filters = [self.syns_seen, self.noloss]
	#self.filters = [self.syns_seen]
        self.filters = [self.cli_syn_seen]
	#self.filters = []

############################################################################

    def counters(self):

	#
	# Array to hold filter stats
	#

	self.ctrs = array('l')
	for i in range(self.nfilt):
	    self.ctrs.append(0)

############################################################################

    def build_filters(self, sstr):

	#
	# Append filters specified in given c.l. arg 
	#

	print 'Using filters %s' % (sstr)
	for f in string.splitfields(sstr, ','):
	    #print f
	    #print '%d' % (string.atoi(f))
	    key = string.atoi(f)
	    try:
		filt = self.fdict[key]
		#filter.append(filtdict[string.atoi(f)][0])
            except KeyError:
		print 'Tfilter: unknown tfilt value %d' % (key)
		self.help()
		sys.exit(1)
                
        self.filters.append(filt[0])

############################################################################

    def report(self):

	#
	# Report filter failures
	#
	rep = []
	for i in range(self.nfilt):
	    if self.ctrs[i]:
		rep.append((self.fdict[i][1], self.ctrs[i]))

	return rep
############################################################################

    def help(self):
	print 'Reject TCP/HTTP connection based upon HTTP characteristics:'

	for filt in self.flist:
	    print '\t%3d %s' % (filt[0], filt[2])

############################################################################

    #
    # Pass everything
    #
    def pass_all(self, connrec, translist):
	return 1

############################################################################  

    #
    # Pass persistant connections with multiple transactions
    #
    def pers_and_multi(self, connrec, translist):

	if connrec.http_persistent() and connrec.http_ntrans() > 1:
	    return 1
	else:
	    self.ctrs[10] = self.ctrs[10] + 1
	    return 0

############################################################################

    #
    # Pass where browser host is a Mac 
    #
    def browsing_on_a_Mac(self, connrec, translist):
	for t in translist:
	    if not t.http_cli_isvalid():
		continue
	    uagent = t.get_uagent()
	    if uagent and string.find(uagent, 'Macin') >= 0:
		return 1

	self.ctrs[50] = self.ctrs[50] + 1
	return 0 

############################################################################

    #
    # Pass where browser host is a Mac_PowerPC 
    #
    def browsing_on_a_MacP(self, connrec, translist):
	for t in translist:
	    if not t.http_cli_isvalid():
		continue
	    uagent = t.get_uagent()
	    if uagent and string.find(uagent, 'Mac_Power') >= 0:
		return 1

	self.ctrs[51] = self.ctrs[51] + 1
	return 0 

############################################################################

    #
    # Pass only connections with > 20 pkts
    #
    def long_conn(self, connrec, translist):
	if connrec.tot_pkts() > 20:
	    return 1
	else:
	    self.ctrs[12] = self.ctrs[12] + 1
	    return 0   

############################################################################ 

    #
    # Pass only when full connection open seen
    #
    def syns_seen(self, connrec, translist):
	state = connrec.get_flags()
	if (state & TCP_SERV_SYN) and (state & TCP_CLI_SYN):
	    return 1
	else:
	    self.ctrs[1] = self.ctrs[1] + 1
	    return 0

############################################################################ 

    #
    # Pass only when client SYN seen
    #
    def cli_syn_seen(self, connrec, translist):
	state = connrec.get_flags()
	if (state & TCP_CLI_SYN):
	    return 1
	else:
	    self.ctrs[1] = self.ctrs[1] + 1
	    return 0

############################################################################

    #
    # Pass only when no gaps or retransmissions
    #
    def noloss(self, connrec, translist):
	if connrec.no_rtmts_or_gaps():
	    return 1
	else:
	    self.ctrs[2] = self.ctrs[2] + 1
	    return 0

############################################################################

    #
    # Pass only when gaps or retransmissions
    #
    def loss(self, connrec, translist):
	if connrec.no_rtmts_or_gaps():
	    return 0
	else:
	    self.ctrs[3] += 1
	    return 1  

############################################################################

	

	
