Ejemplo n.º 1
0
    def _buildAcls(self):
        for aclname, aclrules in self.config.match.iteritems():
            key = eossdk.AclKey(aclname, eossdk.ACL_TYPE_IPV4)

            # todo support ipv6 also
            for i, rule in enumerate(aclrules):
                aclRule = eossdk.AclRuleIp()

                if rule.proto:
                    pr = PROTOCOLS.get(rule.proto.lower())
                    if pr:
                        aclRule.ip_protocol_is(pr)
                    else:
                        sys.stderr.write('Invalid protocol name "%s"',
                                         rule.proto)

                if rule.src_ip:
                    try:
                        srcPfx = eossdk.IpPrefix(rule.src_ip)
                        addr = eossdk.IpAddrMask(srcPfx.network(),
                                                 srcPfx.prefix_length())
                        aclRule.source_addr_is(addr)
                    except eossdk.Error:
                        sys.stderr.write('bad IP address: %s\n', rule.src_ip)
                        continue

                if rule.dst_ip:
                    try:
                        dstPfx = eossdk.IpPrefix(rule.dst_ip)
                        addr = eossdk.IpAddrMask(dstPfx.network(),
                                                 dstPfx.prefix_length())
                        aclRule.destination_addr_is(addr)
                    except eossdk.Error:
                        sys.stderr.write('bad IP address: %s\n', rule.dst_ip)
                        continue

                if rule.sport:
                    try:
                        spec = self._buildPortSpec(rule.sport)
                    except ConfigError as e:
                        sys.stderr.write('Invalid port spec %r: %s\n', spec, e)
                    else:
                        aclRule.source_port_is(spec)

                if rule.dport:
                    try:
                        spec = self._buildPortSpec(rule.dport)
                    except ConfigError as e:
                        sys.stderr.write('Invalid port spec %r: %s\n', spec, e)
                    else:
                        aclRule.destination_port_is(spec)

                self.acl_mgr.acl_rule_set(key, i, aclRule)
        self.acl_mgr.acl_commit()
Ejemplo n.º 2
0
   def _buildClassMaps(self):
      classifiers = self.config_.classifiers
      for name, classifier in classifiers.iteritems():
         key = eossdk.PolicyMapKey(name, eossdk.POLICY_FEATURE_PBR)
         class_map = eossdk.ClassMap(key)

         for rule_index, match in enumerate(classifier.matches):
            print 'Adding to class map:', name, 'seq:', str(rule_index + 1), match
            rule_key = eossdk.AclKey(match.acl_name, eossdk.ACL_TYPE_IPV4)
            rule = eossdk.ClassMapRule(rule_key)
            # Set the action for the rule
            class_map.rule_set(rule_index + 1, rule)
         self.class_map_mgr.class_map_is(class_map)
         cm = self.class_map_mgr.class_map(key)
         print 'Set class map:', name, 'now with', len(cm.rules()), 'rules'
Ejemplo n.º 3
0
 def on_initialized(self):
     self.tracer.trace1("Initialized")
     self.agentMgr_.status_set("Status:", "Administratively Up")
     #Set up all our options.
     global REDIRECTCOMMUNITY
     if self.agentMgr_.agent_option("REDIRECTCOMMUNITY"):
         self.on_agent_option(
             "REDIRECTCOMMUNITY",
             self.agentMgr_.agent_option("REDIRECTCOMMUNITY"))
     else:
         #global REDIRECTCOMMUNITY
         #We'll just use the default community specified by global variable
         self.agentMgr_.status_set("REDIRECTCOMMUNITY:",
                                   "%s" % REDIRECTCOMMUNITY)
     # initialize the ACL
     global REDIRECTACL
     self.aclKey = eossdk.AclKey(REDIRECTACL, eossdk.ACL_TYPE_IPV4)
Ejemplo n.º 4
0
   def process_config(self):
      """Critical function; processes configuration and rules description files.
      Called upon initialization and then subsequently whenever inotify indicates
      the configuration file has changed on disk."""

      self.tracer.trace0("Processing config")
      syslog.syslog("Attempting to process configuration file(s)")

      # Time stamp for performance evaluation
      start_time = time.time()
      self.start_time = start_time
      
      # Attempt to parse ACLerate_config_file
      # Initially, attempt to acquire the lock to ensure file not modified
      # by another entity while it is being processed here.
      syslog.syslog("Attempting to open, lock and parse %s" % self.config_file)
      try:
          with open(self.config_file) as acl_config_file:
              for i in xrange(file_lock_attempt):
                  try:
                      fcntl.flock(acl_config_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
                      break
                  except IOError:
                      sys.stderr.write("Attempt %s to lock %s "
                                       "failed\n" % (str(i+1), self.config_file))
                  time.sleep(file_lock_interval)
              else:
                  syslog.syslog("All %s attempts to lock %s "
                                "failed" % (str(file_lock_attempt), self.config_file))
                  sys.stderr.write("All %s attempts to lock %s "
                                   "failed\n" % (str(file_lock_attempt), self.config_file))
                  return
              syslog.syslog("%s opened & locked successfully. Now parse" % self.config_file)
              acl_config_list = json.load(acl_config_file)
      except IOError:
          syslog.syslog("Cannot open %s" % self.config_file)
          sys.stderr.write("Cannot open %s\n" % self.config_file)
          return

      for acl_config in acl_config_list:

          command = acl_config.get("command")
          name = acl_config.get("name")
          acl_type = acl_config.get("type")
          interface = acl_config.get("interface")
          operation = acl_config.get("operation")
          direction = acl_config.get("direction")
          rules_file = acl_config.get("rules")
          counting = acl_config.get("counting")

          # Sanity check ACL parameters (before potentially
          # iterating over thousands of rules!).  If invalid, skip
          # processing rest of this ACL and continue to next ACL
          if not acl_validate(command, name, acl_type, direction, counting):
              syslog.syslog("Invalid ACL input data")
              sys.stderr.write("Invalid ACL input data\n")
              continue

          syslog.syslog("Processing %s command for %s ACL %s" % (command, acl_type, name))

          # Convert external ACL type to SDK's type
          sdk_type = acl_type_convert(acl_type)
          if sdk_type is None:
              syslog.syslog("Invalid ACL type")
              sys.stderr.write("Invalid ACL type specified\n")
              continue

          # Get handle to ACL.
          acl_key = eossdk.AclKey(str(name), sdk_type)

          # If input command is to delete the ACL, simply call the appropriate
          # SDK API and continue onto next ACL in the list.  i.e. no need to be
          # concerned with interfaces, rules etc.
          if command.lower() == "delete-acl":
              syslog.syslog("About to delete %s ACL %s" % (acl_type, name))
              self.acl_mgr.acl_del(acl_key)
              # Now call commit to actually push changes to HW.
              self.acl_mgr.acl_commit()
              continue

          intf_id = None
          # Next, if an interface is specified, verify it actually exists
          # and correct parameters have been specified
          if interface:
              intf_id = self.interface_validate(interface, operation, direction)
              if intf_id:
                  # Convert external direction to SDK's type
                  sdk_direction = direction_convert(direction)
                  if sdk_direction is None:
                      syslog.syslog("Invalid direction %s specified" % direction)
                      sys.stderr.write("Invalid direction %s specified\n" % direction)
                      continue
              else:
                  syslog.syslog("Invalid interface %s specified" % interface)
                  sys.stderr.write("Invalid interface %s specified\n" % interface)
                  continue

          # Set ACL counting behaviour if specified.  If not, will
          # simply fallback to default ACL behaviour.
          if counting:
              if counting.lower() == "true":
                  self.acl_mgr.acl_counters_enabled_set(acl_key, True)
              if counting.lower() == "false":
                  self.acl_mgr.acl_counters_enabled_set(acl_key, False)

          # Rules files is needed.  Does it actually exist?
          # Is a comprehensive unwind needed in the error case?
          if rules_file is None:
              syslog.syslog("Need to add/remove rules but no rule info file specified")
              sys.stderr.write("Need to add/remove rules but no rule info file specified\n")
              continue
          
          # Attempt to parse rules_file
          # Initially, attempt to acquire the lock to ensure file not modified
          # by another entity while it is being processed here.
          syslog.syslog("Attempting to open, lock and parse %s" % rules_file)
          try:
              with open(rules_file) as rule_listing_file:
                  for i in xrange(file_lock_attempt):
                      try:
                          fcntl.flock(rule_listing_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
                          break
                      except IOError:
                          sys.stderr.write("Attempt %s to lock %s "
                                           "failed\n" % (str(i+1), rule_file))
                      time.sleep(file_lock_interval)
                  else:
                      syslog.syslog("All %s attempts to lock %s "
                                    "failed" % (str(file_lock_attempt), rules_file))
                      sys.stderr.write("All %s attempts to lock %s "
                                       "failed\n" % (str(file_lock_attempt), rules_file))
                      return
                  syslog.syslog("%s opened & locked successfully. Now parse" % rules_file)
                  rule_list = json.load(rule_listing_file)
          except IOError:
              syslog.syslog("Cannot open %s" % rules_file)
              sys.stderr.write("Cannot open %s\n" % rules_file)
              continue

          # Now iterate over all rules
          for index, rule in enumerate(rule_list):
              number = rule.get("number")
              source = rule.get("source")
              destination = rule.get("destination")
              protocol = rule.get("protocol")
              action = rule.get("action")
              log = rule.get("log")

              # Rule must have a sequence number.
              if number is None:
                  syslog.syslog("Rule must have a number")
                  sys.stderr.write("Rule must have a number\n")
                  continue
    
              # If input command is to delete the rule, simply call the SDK API
              # and continue to next rule in the list.
              # i.e. no need to be concerned with addresses, protocols etc.
              if command.lower() == "delete-rule":
                  self.acl_mgr.acl_rule_del(acl_key, int(number))
                  continue

              # If here, then the command must be to add rule.
              # So verify if rule data supplied is valid.
              if rule_validate(number, source, destination, action) == False:
                  syslog.syslog("Invalid rule input data")
                  sys.stderr.write("Invalid rule input data\n")
                  continue

              # Create IP ACL rule object.  Used for IPv4 and IPv6 ACLs but
              # different object needed for Ethernet ACLs.
              # (Perhaps create object with all rule info and invoke
              # functions to process for ACL, IPv4, IPv6 etc?
              # Needs more thought on optimal way to handle different ACL type)
              acl_rule = eossdk.AclRuleIp()

              # Now parse the rule data and invoke appropriate SDK
              # APIs to create requisite data structures.
              if source:
                  try:
                      # How is "any" handled? 0.0.0.0/0?
                      if source == "any":
                          source = "0.0.0.0/0"

                      # String to IP address conversion of source?
                      sdk_prefix = eossdk.IpPrefix(str(source))
                      sdk_addr = eossdk.IpAddrMask(sdk_prefix.network(),
                                                       sdk_prefix.prefix_length())
                      acl_rule.source_addr_is(sdk_addr)
                  except eossdk.Error:
                      syslog.syslog("Error processing source address %s" % source)
                      sys.stderr.write("Error processing source address %s\n" % source)
                      continue

              if destination:
                  try:
                      # How is "any" handled? 0.0.0.0/0?
                      if destination == "any":
                          destination = "0.0.0.0/0"

                      # String to IP address conversion of destination?
                      sdk_prefix = eossdk.IpPrefix(str(destination))
                      sdk_addr = eossdk.IpAddrMask(sdk_prefix.network(),
                                                       sdk_prefix.prefix_length())
                      acl_rule.destination_addr_is(sdk_addr)
                  except eossdk.Error:
                      syslog.syslog("Error processing destination address %s" % destination)
                      sys.stderr.write("Error processing destination address %s\n" % destination)
                      continue

              if protocol:
                  protocol_number = protocol_validate(protocol, sdk_type)
                  if protocol_number:
                      acl_rule.ip_protocol_is(protocol_number)
                  else:
                      syslog.syslog("Error processing protocol %s" % protocol)
                      sys.stderr.write("Error processing protocol %s\n" % protocol)
                      continue

              # Previously verified that action is 'permit' or 'deny'
              if action:
                  try:
                      if action.lower() == "permit":
                          acl_rule.action_is(eossdk.ACL_PERMIT)
                      else:
                          acl_rule.action_is(eossdk.ACL_DENY)
                  except:
                      syslog.syslog("Error processing action %s" % action)
                      sys.stderr.write("Error processing action %s\n" % action)
                      continue

              if log:
                  try:
                      if log.lower() == "true":
                          acl_rule.log_is(True)
                      else:
                          acl_rule.log_is(False)
                  except:
                      syslog.syslog("Error processing log %s" % log)
                      sys.stderr.write("Error processing log %s\n" % log)
                      continue
 
              # Now add this rule to ACL, with appropriate sequence number
              # Should only ever be here when adding rules.... paranoid check.
              if command.lower() == "add-rule":
                  self.acl_mgr.acl_rule_set(acl_key, int(number), acl_rule)

          parsing_time = time.time()
          self.parsing_time = parsing_time

          self.parsing_duration = parsing_time - start_time

          syslog.syslog("Time to parse config files for ACL %s "
                           "is %ss" % (name, self.parsing_duration))

          self.rule_count = index+1
          syslog.syslog("Processing %s rules complete.  "
                        "Now commit ACL %s to HW" % (index+1, name))
          # Now call commit to actually push changes to HW.
          self.acl_mgr.acl_commit()

          # Should ACL be attached or detached from interface?
          if intf_id:
              if operation.lower() == "attach":
                  syslog.syslog("Attaching ACL %s to interface %s "
                                "%sbound" % (name, interface, direction.lower()))
                  self.acl_mgr.acl_apply(acl_key, intf_id, sdk_direction, True)
              if operation.lower() == "detach":
                  syslog.syslog("Detaching ACL %s from interface %s "
                                "%sbound" % (name, interface, direction.lower()))
                  self.acl_mgr.acl_apply(acl_key, intf_id, sdk_direction, False)