Changeset 114

Show
Ignore:
Timestamp:
05/12/05 04:17:19 (4 years ago)
Author:
athomas
Message:
  • We are arriving at usefulness.
  • Factored out object resolution from Firewall class into Resolver
  • Resolver can import port objects from /etc/services
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • fwc/trunk/Firewall.py

    r112 r114  
    33 
    44class Firewall: 
    5         def __init__(self, name): 
    6                 self.rules = [] 
     5        """ 
     6                The Firewall class contains all  
     7        """ 
     8        class Error(Exception): pass 
     9        class InvalidIndex(Error): pass 
     10        class InvalidObject(Error): pass 
     11        class InvalidRule(Error): pass 
     12 
     13        def __init__(self, name, resolver): 
     14                self.__rules = [] 
    715                self.name = name 
    8                 self.ip = {} 
    9                 self.network = {} 
    10                 self.port = {} 
    11                 # Set up default objects 
    12                 self.add_object(Object(Object.NETWORK, 'any', '0.0.0.0/0', 'Any network address')) 
    13                 self.add_object(Object(Object.IP, 'any', '0.0.0.0', 'Any IP address')) 
    14                 self.add_object(Object(Object.PORT, 'any', '0-65535', 'Any port')) 
    15  
    16         def resolve_object(self, type, name): 
    17                 map = getattr(self, type) 
    18                 if map and name in map: 
    19                         return map[name] 
    20                 return Object(type, name, name) 
    21  
    22         def resolve_network(self, network): 
    23                 return self.resolve_object('network', network) 
    24  
    25         def resolve_ip(self, ip): 
    26                 return self.resolve_ip('ip', ip) 
    27  
    28         def resolve_port(self, port): 
    29                 return self.resolve_port('port', port) 
     16                self.resolver = resolver 
    3017 
    3118        def resolve_rule(self, rule): 
    3219                try: 
    3320                        rule = int(rule) 
    34                         if rule >= 0 and rule < len(self.rules): 
     21                        if rule >= 0 and rule < len(self.__rules): 
    3522                                return int(rule) 
    3623                except TypeError: 
     
    4027                try: 
    4128                        if where == 'top': 
    42                                 self.rules.insert(0, rule) 
     29                                self.__rules.insert(0, rule) 
    4330                                return 0 
    4431                        elif where == 'bottom' : 
    45                                 self.rules.append(rule) 
    46                                 return len(self.rules) - 1 
     32                                self.__rules.append(rule) 
     33                                return len(self.__rules) - 1 
    4734                        elif where == 'before': 
    48                                 self.rules.insert(index, rule) 
     35                                self.__rules.insert(index, rule) 
    4936                                return index 
    5037                        elif where == 'after': 
    51                                 self.rules.insert(index + 1, rule) 
     38                                self.__rules.insert(index + 1, rule) 
    5239                                return index + 1 
    5340                        elif where == 'replace' : 
    54                                 self.rules[index] = rule 
     41                                self.__rules[index] = rule 
    5542                                return index 
    5643                        else: 
    57                                 raise IndexError("invalid location '%s' for rule addition" % where) 
     44                                raise Firewall.InvalidIndex("invalid location '%s' for rule addition" % where) 
    5845                except IndexError: 
    59                         error("Invalid ruleset index %s" % index) 
    60                         return None 
     46                        raise Firewall.InvalidIndex("Invalid ruleset index %s" % index) 
    6147 
    6248        def move(self, old, new): 
     49                """ Move rule from index old to before index new """ 
    6350                if old == new: return 
    6451                try: 
    65                         rule = self.rules.pop(old) 
     52                        rule = self.__rules.pop(old) 
    6653                        try: 
    6754                                if new > old: 
    68                                         self.rules.insert(new - 1, rule) 
     55                                        self.__rules.insert(new - 1, rule) 
    6956                                else: 
    70                                         self.rules.insert(new, rule) 
     57                                        self.__rules.insert(new, rule) 
    7158                        except: 
    72                                 self.rules.insert(old, rule) 
     59                                self.__rules.insert(old, rule) 
    7360                                raise 
    7461                except IndexError: 
    75                         error("Invalid ruleset index %s or %s" % (old, new)) 
     62                        raise InvalidRule("Invalid ruleset index %s or %s" % (old, new)) 
    7663 
    7764        def remove(self, index): 
     65                """ Remove a set of rules. Indices are guaranteed to be valid across 
     66                        the entire remove operation. """ 
    7867                if type(index) is not list: index = [ index ] 
    7968                try: 
    8069                        for i in index: 
    81                                 self.rules[i] = None 
     70                                self.__rules[i] = None 
    8271                        newrules = [] 
    83                         for i in self.rules: 
     72                        for i in self.__rules: 
    8473                                if i: newrules.append(i) 
    85                         self.rules = newrules 
     74                        self.__rules = newrules 
    8675                except IndexError: 
    87                         error("Invalid rule index %s" % index) 
     76                        raise InvalidRule("Invalid rule index %s" % index) 
    8877                 
    89         def add_object(self, object): 
    90                 map = getattr(self, object.type) 
    91                 if object.name in map: 
    92                         error("%s object '%s' already exists" % (object.type.title(), object.name)) 
    93                 else: 
    94                         map[object.name] = object 
    95          
    96         def remove_object(self, object): 
    97                 try: 
    98                         del(getattr(self, object.type)[object.name]) 
    99                 except IndexError: 
    100                         error("Object '%s' not in ruleset" % object.name) 
     78        def get_rule(self, rule): 
     79                return self.__rules[rule] 
    10180 
     81        def get_rules(self): 
     82                return self.__rules 
     83 
     84        def __iter__(self): 
     85                return iter(self.__rules) 
  • fwc/trunk/fwc

    r112 r114  
    11#!/usr/bin/python 
    22 
    3 from CLI import * 
     3from CLI.CLI import * 
    44import types 
    55import re 
     
    1010from Object import Object 
    1111from Firewall import Firewall 
     12from Resolver import Resolver 
     13from util import * 
    1214 
    1315CONF_DIR = "/etc/fwcrc" 
     
    1517# Globally useful stuff 
    1618  
     19resolver = Resolver() 
    1720firewalls = {} 
    18 firewall = firewalls['DEFAULT'] = Firewall() 
     21firewall = None 
     22firewall = Firewall("localhost", resolver) 
    1923 
    2024def to_list(value): 
     
    2226        return value 
    2327 
    24 def info(message): 
    25         print "OK %s" % message 
    26  
    27 def warning(message): 
    28         print "WRN %s" % message 
    29  
    30 def error(message): 
    31         print "ERR %s" % message 
    32  
    33 def fatal(message): 
    34         print "FTL %s" % message 
    35         sys.exit(1) 
    36  
    3728def check_port_protocol(context): 
    3829        return 'protocol' in context and context['protocol'] in [ 'tcp', 'udp' ] 
    3930 
     31def have_firewall(context): 
     32        """ Return true if the current firewall is have_firewall. """ 
     33        return firewall 
     34 
     35def have_modifiable_firewall(context): 
     36        return firewall 
     37 
    4038# Help extractors 
    4139  
    42 def help_ip(context): 
    43         help = { '<ip>' : 'IP address.'} 
    44         for o in firewall.ip.values(): 
    45                 text = o.description or "IP address object %s" % o.name 
    46                 help[o.name] = text + " (%s)" % o.value 
    47         return help 
    48                  
    4940def help_network(context): 
    5041        help = { '<network>' : 'Network address.'} 
    51         for o in firewall.network.values(): 
     42        for o in resolver.get_objects('network'): 
    5243                text = o.description or "Network object %s" % o.name 
    5344                help[o.name] = text + " (%s)" % o.value 
    5445        return help 
    5546                 
    56 def help_network_ip(context): 
    57         help = {} 
    58         help.update(help_ip(context)) 
    59         help.update(help_network(context)) 
    60         return help 
    61  
    6247def help_port(context): 
    6348        help = { '<port>' : 'Port.'} 
    64         for o in firewall.port.values(): 
     49        for o in resolver.get_objects('port'): 
    6550                text = o.description or "Port object %s" % o.name 
    6651                help[o.name] = text + " (%s)" % o.value 
     
    7661  
    7762def NETWORK(context, str): 
    78         return re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}', str) \ 
     63        return re.match(Object.NETWORK_PATTERN, str) \ 
    7964                or str in help_network(context) 
    8065 
    81 def NETWORK_IP(context, str): 
    82         return re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:/\d{1,2})?', str) \ 
    83                 or str in help_network(context) \ 
    84                 or str in help_ip(context) 
    85  
    86 def IP(context, str): 
    87         return re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', str) \ 
    88                 or str in help_ip(context) 
    89  
    9066def PORT(context, str): 
    91         return re.match(r'\d{1,5}', str) \ 
     67        return re.match(Object.PORT_PATTERN, str) \ 
    9268                or str in help_port(context) 
    9369 
     
    9874def RULE(context, str): 
    9975        try: 
    100                 return int(str) >= 0 and int(str) < len(firewall.rules
     76                return int(str) >= 0 and int(str) < len(firewall.get_rules()
    10177        except: 
    10278                return False 
    10379 
    10480def FIREWALL(context, str): 
    105         print help_firewall(context) 
    10681        return str in help_firewall(context) 
    10782 
     
    12499        try: 
    125100                old = int(old) 
    126                 new = firewall.add(firewall.rules[old], where, index and int(index) or None) 
     101                new = firewall.add(firewall.get_rule(old), where, index and int(index) or None) 
    127102                if new < old: old += 1 
    128103                firewall.remove(old) 
     
    132107 
    133108def list_ruleset(context): 
    134         for ruleno, rule in enumerate(firewall.rules): 
    135                 cmd = "%s" % rule.action 
     109        for ruleno, rule in enumerate(firewall.get_rules()): 
     110                cmd = "^B%s^B" % rule.action 
    136111                if rule.state != 'new': 
    137                         cmd += " state " + rule.state + "
     112                        cmd += " state ^B" + rule.state + "^B
    138113                if rule.protocol: 
    139                         cmd += " " + rule.protocol + "
     114                        cmd += " ^B" + rule.protocol + "^B
    140115                if rule.source or rule.sport: 
    141116                        cmd += " from" 
    142117                        if rule.source: 
    143                                 cmd += " " + ' '.join(rule.source) + "
     118                                cmd += " ^B" + ' '.join(rule.source) + "^B
    144119                        if rule.sport: 
    145                                 cmd += " port " + ' '.join(rule.sport) + "
     120                                cmd += " port ^B" + ' '.join(rule.sport) + "^B
    146121                if rule.destination or rule.dport: 
    147122                        cmd += " to" 
    148123                        if rule.destination: 
    149                                 cmd += " " + ' '.join(rule.destination) + "
     124                                cmd += " ^B" + ' '.join(rule.destination) + "^B
    150125                        if rule.dport: 
    151                                 cmd += " port " + ' '.join(rule.dport) + "
     126                                cmd += " port ^B" + ' '.join(rule.dport) + "^B
    152127                if rule.log: 
    153128                        cmd += " log" 
    154129                        if type(rule.log) is str: 
    155                                 cmd += " '%s'" % rule.log 
     130                                cmd += " ^B'%s'^B" % rule.log 
    156131                if rule.description: 
    157                         cmd += " description '%s'" % rule.description 
    158                 print "%3i: %s" % (ruleno, cmd
     132                        cmd += " description ^B'%s'^B" % rule.description 
     133                cprint("^B%3i:^B %s" % (ruleno, cmd)
    159134 
    160135def create_object(context, type, name, value, description = None): 
    161         firewall.add_object(Object(type, name, value, description)) 
    162  
    163 def list_objects(context, type = ['network', 'ip', 'port']): 
     136        try: 
     137                resolver.add_object(Object(type, name, value, description)) 
     138        except Resolver.Error, e: 
     139                error(e) 
     140 
     141 
     142def list_objects(context, type = Resolver.get_object_types()): 
    164143        for t in to_list(type): 
    165                 objects = getattr(firewall, t) 
    166                 print "%s objects" % t.title() 
    167                 for k in sorted(objects): 
    168                         o = objects[k] 
    169                         str = "  %s %s" % (o.name, o.value) 
     144                objects = resolver.get_objects(t) 
     145                for o in sorted(objects): 
     146                        str = "%s %s %s" % (o.type, o.name, o.value) 
    170147                        if o.description: str += " '%s'" % o.description 
    171148                        print str 
     
    234211cli = CLI({ 
    235212        'accept|drop|reject' : { 
     213                IF : have_modifiable_firewall, 
    236214                GLOBAL_LABEL : 'commands', 
    237215                'state' : { 
     
    267245                        HELP : 'Match source network or port.', 
    268246                        IF : lambda ctx: ('protocol' in ctx and ctx['protocol'] in ['tcp', 'udp'] and not 'sport' in ctx) or not 'source' in ctx, 
    269                         NETWORK_IP : { 
     247                        NETWORK : { 
    270248                                VAR : 'source', 
    271249                                LABEL : 'source', 
     
    284262                                        IF : check_port_protocol, 
    285263                                }, 
    286                                 HELP : help_network_ip
     264                                HELP : help_network
    287265                        }, 
    288266                        'port' : { 
     
    312290                        IF : lambda ctx: ('protocol' in ctx and ctx['protocol'] in ['tcp', 'udp'] and not 'dport' in ctx) or not 'destination' in ctx, 
    313291                        UNLESS_VAR : [ 'dport', 'destination' ], 
    314                         NETWORK_IP : { 
     292                        NETWORK : { 
    315293                                LABEL : 'destination', 
    316294                                VAR : 'destination', 
     
    328306                                        HELP : 'Match destination port.', 
    329307                                }, 
    330                                 HELP : help_network_ip
     308                                HELP : help_network
    331309                        }, 
    332310                        'port' : { 
     
    363341        'object' : { 
    364342                HELP : 'Manage ruleset objects.', 
     343                'import' : { 
     344                        HELP : 'Import system default objects.', 
     345                        ACTION : lambda x: resolver.populate_defaults(), 
     346                }, 
    365347                'create' : { 
    366348                        HELP : 'Create a ruleset object.', 
     
    368350                                VAR : 'type', 
    369351                                HELP : 'Create network object.', 
    370                                 '\w+' : { 
     352                                Object.NAME_PATTERN : { 
    371353                                        VAR : 'name', 
    372354                                        HELP : { '<name>' : 'Name of object to create.' }, 
    373                                         '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}' : { 
     355                                        Object.NETWORK_PATTERN : { 
    374356                                                VAR : 'value', 
    375357                                                HELP : { '<network>' : 'Network.' }, 
     
    383365                                }, 
    384366                        }, 
    385                         'default' : { 
    386                                 HELP : 'Create objects from system defaults.', 
    387                         }, 
    388                         Object.IP : { 
    389                                 VAR : 'type', 
    390                                 HELP : 'Create IP address object.', 
    391                                 '\w+' : { 
    392                                         VAR : 'name', 
    393                                         HELP : { '<name>' : 'Name of object to create.' }, 
    394                                         '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' : { 
    395                                                 VAR : 'value', 
    396                                                 HELP : { '<ip>' : 'IP address.' }, 
    397                                                 ACTION : create_object, 
    398                                                 '.+' : { 
    399                                                         VAR : 'description', 
    400                                                         HELP : { '<description>' : 'Description of object.' }, 
    401                                                         ACTION : create_object, 
    402                                                 }, 
    403                                         }, 
    404                                 }, 
    405                         }, 
    406367                        Object.PORT : { 
    407368                                VAR : 'type', 
    408369                                HELP : 'Create port object.', 
    409                                 '\w+' : { 
     370                                Object.NAME_PATTERN : { 
    410371                                        VAR : 'name', 
    411372                                        HELP : { '<name>' : 'Name of object to create.' }, 
    412                                         '\d{1,5}' : { 
     373                                        Object.PORT_PATTERN : { 
    413374                                                VAR : 'value', 
    414375                                                HELP : { '<port>' : 'Port.' }, 
     
    424385                }, 
    425386                'delete' : { 
    426                         HELP : 'Create a new ruleset object.', 
    427                         'network|ip|port' : { 
     387                        HELP : 'Delete a ruleset object.', 
     388                        'network|port' : { 
    428389                                VAR : 'type', 
    429390                                HELP : { 
    430391                                        'network' : 'Remove network object.', 
    431                                         'ip' : 'Remove IP address object.', 
    432392                                        'port' : 'Remove port object.', 
    433393                                }, 
     
    440400                                ACTION : list_objects, 
    441401                        }, 
    442                         'network|ip|port' : { 
     402                        'network|port' : { 
    443403                                VAR : 'type', 
    444404                                HELP : { 
    445405                                        'network' : 'List network objects.', 
    446                                         'ip' : 'List IP address objects.', 
    447406                                        'port' : 'List port objects.', 
    448407                                }, 
     
    452411        }, 
    453412        'delete' : { 
     413                IF : have_modifiable_firewall, 
    454414                HELP : 'Remove rule(s) from the ruleset.', 
    455415                LABEL : 'rule', 
     
    462422        }, 
    463423        'list' : { 
     424                IF : have_firewall, 
    464425                HELP : 'List ruleset.', 
    465426                ACTION : list_ruleset, 
     
    467428        HELP : "Commands to manage the ruleset.", 
    468429        'move' : { 
     430                IF : have_modifiable_firewall, 
    469431                HELP : 'Move rule.', 
    470432                RULE : { 
     
    483445                'acquire' : { 
    484446                        HELP : 'Acquire a firewall for management.', 
     447                        '\w+' : { 
     448                        }, 
    485449                }, 
    486450                'list' : { 
     
    498462 
    499463cli_inject_text = '' 
     464bind_key = hasattr(readline, 'bind_key') and readline.bind_key or None 
     465force_redisplay = hasattr(readline, 'force_redisplay') and readline.force_redisplay or None 
     466set_input_hook = hasattr(readline, 'set_input_hook') and readline.set_input_hook or None 
     467cursor = hasattr(readline, 'cursor') and readline.cursor or None 
    500468 
    501469def cli_completion(text, state): 
     
    530498                readline.insert_text("?") 
    531499                return 
    532         if hasattr(readline, 'bind_key')
    533                 if result.context.parsed_tokens and result.context.parsed_tokens[-1].start() >= readline.cursor(): 
     500        if cursor
     501                if result.context.parsed_tokens and result.context.parsed_tokens[-1].start() >= cursor(): 
    534502                        return 
    535503        if need_linefeed: 
    536504                print 
    537505        format_help(result.help()) 
    538         if hasattr(readline, 'bind_key')
    539                 readline.force_redisplay() 
     506        if force_redisplay
     507                force_redisplay() 
    540508 
    541509def cli_help(key, count): 
     
    548516                        length = len(h[0]) 
    549517        for h in help: 
    550                 print "  %s %s" % (h[0] + (length - len(h[0])) * ' ', h[1]
     518                cprint("  ^B%s^B %s" % (h[0] + (length - len(h[0])) * ' ', h[1])
    551519 
    552520readline.set_completer(cli_completion) 
    553521readline.set_startup_hook(cli_injector) 
    554 if hasattr(readline, 'bind_key'): 
    555         readline.bind_key(ord('?'), cli_help) 
    556  
    557 print \ 
    558 """Welcome to the FireWall Console (FWC) 
    559  
    560 Press ? at any time for help.""" 
     522# Use custom readline extensions not in 2.4 
     523if bind_key and set_input_hook: 
     524        bind_key(ord('?'), cli_help) 
     525        #set_input_hook(timeout) 
     526 
     527cprint(\ 
     528"""Welcome to the ^BFireWall Console^B (^BFWC^B) 
     529 
     530Press ^B?^B at any time for help.""" 
     531
    561532while True: 
    562533        command = '' 
    563534        try: 
    564535                command = raw_input("fwc> ") 
     536        except KeyboardInterrupt: 
     537                print 
    565538        except EOFError: 
    566539                print 
     
    584557 
    585558                if result.state == Result.OK: 
    586                         result() 
     559                        try: 
     560                                result() 
     561                        except Firewall.Error, e: 
     562                                error(e) 
    587563                else: 
    588564                        if not result.token: 
  • fwc/trunk/Object.py

    r112 r114  
    11class Object: 
     2        # Types 
    23        NETWORK = 'network' 
    3         IP = 'ip' 
    44        PORT = 'port' 
     5 
     6        NETWORK_PATTERN = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:/\d{1,2})?' 
     7        PORT_PATTERN = r'\d{1,5}' 
     8 
     9        # Regex matching a valid object name 
     10        NAME_PATTERN = '[\w.-]+' 
    511 
    612        def __init__(self, type, name, value, description = ""): 
     
    1016                self.description = description 
    1117 
     18        def __repr__(self): 
     19                return "%s(%s, %s, %s)" % (self.type, repr(self.name), repr(self.value), repr(self.description))