Skip to main content

Python package to parse and manage Cisco ACL (Access Control List)

Project description

https://img.shields.io/pypi/v/cisco-acl.svg https://img.shields.io/pypi/pyversions/cisco-acl.svg

cisco-acl

Python package to parse and manage Cisco ACLs (Access Control Lists).

Supported platforms:

  • Cisco IOS

  • Cisco Nexus NX-OS

Main features:

  • Changes the IOS syntax to NX-OS syntax and vice vera

  • Represents TCP/UDP ports and IP protocols as numbers or as well-known names

  • Represents addresses in multiple formats: subnet, wildcard, prefix, IPv4Network

  • Add and remove sequence numbers

  • Support address group objects

  • Search and remove ACEs in the shadow (rules without hits)

  • Groups ACEs to blocks. After sorting, the order of ACEs within a group does not change

Acronyms

Acronym

Definition

ACL

Access Control List

ACE

Access Control Entry

ACEs

Multiple Access Control Entries

Acl.items

List of objects: Ace, AceGroup, Remark

Requirements

Python >=3.8

Installation

Install the package from pypi.org release

pip install cisco-acl

or install the package from github.com repository

pip install git+https://github.com/vladimirs-git/cisco-acl

or install the package from github.com release

pip install https://github.com/vladimirs-git/cisco-acl/archive/refs/tags/2.1.0.tar.gz

acls()

cisco_acl.acls(config, platform, group_by) Creates Acl objects based on the “show running-config” output. Support address group objects. Each ACE line is treated as an independent Ace element (default) or ACE lines can be grouped to AceGroup by text in remarks (param group_by)

Parameter

Type

Description

config

str

Cisco config, “show running-config” output

platform

str

Platform: “ios”, “nxos” (default “ios”)

names

List[str]

Parse only ACLs with specified names

group_by

str

Startswith in remark line. ACEs group, starting from the Remark, where line startswith group_by, will be applied to the same AceGroup, until next Remark that also startswith group_by

Return

List of Acl objects

Examples

./examples/examples_acls.py

from pprint import pprint
import cisco_acl

config = """
hostname HOSTNAME

ip access-list extended ACL_NAME
  permit tcp 10.0.0.0 0.0.0.255 any eq 21 22 23
  permit tcp host 10.0.0.1 any eq 21
  deny tcp object-group ADDR_GROUP any eq 53
  permit icmp any any

object-group network ADDR_GROUP
 10.1.1.0 255.255.255.252
 host 10.1.1.4

interface Ethernet1
  ip access-group ACL_NAME in
  ip access-group ACL_NAME out
"""
# Create ACL, TCP/UDP ports and IP protocols as well-known names
acls = cisco_acl.acls(config=config, platform="ios")
acl = acls[0]
print(acl.line, "\n")
# ip access-list extended ACL_NAME
#   permit tcp 10.0.0.0 0.0.0.255 any eq ftp 22 telnet
#   permit tcp host 10.0.0.1 any eq ftp
#   deny tcp object-group ADDR_GROUP any eq domain
#   permit icmp any any
# Convert well-known TCP/UDP ports and IP protocols to numbers
# Note, ftp -> 21, telnet -> 23, icmp -> 1
acl.protocol_nr = True
acl.port_nr = True
print(acl.line, "\n")
# ip access-list extended ACL_NAME
#   permit tcp 10.0.0.0 0.0.0.255 any eq 21 22 23
#   permit tcp host 10.0.0.1 any eq 21
#   deny tcp object-group ADDR_GROUP any eq 53
#   permit 1 any any
# *Acl* some attributes demonstration
# Note, "object-group ADDR_GROUP" includes addresses from "object-group network ADDR_GROUP"
print(f"{acl.line=}")
print(f"{acl.platform=}")
print(f"{acl.type=}")
print(f"{acl.indent=}")
print(f"{acl.input=}")
print(f"{acl.output=}")
print(f"{acl.items=}")
print()
# acl.line='ip access-list extended ACL_NAME\n  permit tcp 10.0.0.0 0.0.0.255 any ...
# acl.platform='ios'
# acl.type='extended'
# acl.indent='  '
# acl.input=['interface Ethernet1']
# acl.output=['interface Ethernet1']
# acl.items=[Ace('permit tcp 10.0.0.0 0.0.0.255 any eq ftp 22 telnet'), Ace('perm ...
# Convert well-known TCP/UDP ports and IP protocols to numbers
acl.protocol_nr = True
acl.port_nr = True
print(acl.line, "\n")
# ip access-list extended ACL_NAME
#   permit tcp 10.0.0.0 0.0.0.255 any eq 21 22 23
#   permit tcp host 10.0.0.1 any eq 21
#   deny tcp object-group ADDR_GROUP any eq 53
#   permit 1 any any
# Add sequence numbers
acl.resequence(start=5, step=5)
print(acl.line, "\n")
# ip access-list extended ACL_NAME
#   5 permit tcp 10.0.0.0 0.0.0.255 any eq 21 22 23
#   10 permit tcp host 10.0.0.1 any eq 21
#   15 deny tcp object-group ADDR_GROUP any eq 53
#   20 permit 1 any any
# Delete sequence numbers
acl.resequence(start=0)
print(acl.line, "\n")
# ip access-list extended ACL_NAME
#   permit tcp 10.0.0.0 0.0.0.255 any eq 21 22 23
#   permit tcp host 10.0.0.1 any eq 21
#   deny tcp object-group ADDR_GROUP any eq 53
#   permit 1 any any
# Change syntax from IOS to NX-OS
# Note, "extended" removed from output, range of ports split to multiple lines
acl.platform = "nxos"
print(acl.line, "\n")
# ip access-list ACL_NAME
#   permit tcp 10.0.0.0 0.0.0.255 any eq 21
#   permit tcp 10.0.0.0 0.0.0.255 any eq 22
#   permit tcp 10.0.0.0 0.0.0.255 any eq 23
#   permit tcp host 10.0.0.1 any eq 21
#   deny tcp addrgroup ADDR_GROUP any eq 53
#   permit 1 any any
# Get ACEs in the shadow (in the bottom, without hits)
shadow = acl.shadow()
print(shadow, "\n")
# ['permit tcp host 10.0.0.1 any eq 21']
# Get shading ACEs (in the top)
shading = acl.shading()
print(shading, "\n")
# {'permit tcp 10.0.0.0 0.0.0.255 any eq 21': ['permit tcp host 10.0.0.1 any eq 21']}
# Delete ACEs in the shadow (in the bottom)
shading = acl.delete_shadow()
print(shading)
print(acl.line, "\n")
# {'permit tcp 10.0.0.0/24 any eq 21': ['permit tcp 10.0.0.1/32 any eq 21']}
# ip access-list ACL_NAME
#   permit tcp 10.0.0.0/24 any eq 21
#   permit tcp 10.0.0.0/24 any eq 22
#   permit tcp 10.0.0.0/24 any eq 23
#   deny tcp addrgroup ADDR_GROUP any eq 53
#   permit 1 any any
# Convert object to dictionary
data = acl.data()
pprint(data)
print()
# 'line': 'ip access-list ACL_NAME\n'
#          '  permit tcp 10.0.0.0 0.0.0.255 any eq 21\n'
#          '  permit tcp 10.0.0.0 0.0.0.255 any eq 22\n'
#          '  permit tcp 10.0.0.0 0.0.0.255 any eq 23\n'
#          '  permit tcp host 10.0.0.1 any eq 21\n'
#          '  deny tcp addrgroup ADDR_GROUP any eq 53\n'
#          '  permit 1 any any',
#  'name': 'ACL_NAME',
#  'input': ['interface Ethernet1'],
#  'output': ['interface Ethernet1'],
# 'items': [{'action': 'permit',
#             'dstaddr': {'addrgroup': '',
#                         'ipnet': IPv4Network('0.0.0.0/0'),
#                         'line': 'any',
#                         'prefix': '0.0.0.0/0',
#                         'subnet': '0.0.0.0 0.0.0.0',
#                         'type': 'any',
#                         'wildcard': '0.0.0.0 255.255.255.255'},
# ...
# Crate *Acl* object based on *dict* data
acl = cisco_acl.Acl(**data)
print(acl.line, "\n")
# ip access-list ACL_NAME
#   permit tcp 10.0.0.0/24 any eq 21
#   permit tcp 10.0.0.0/24 any eq 22
#   permit tcp 10.0.0.0/24 any eq 23
#   permit tcp 10.0.0.1/32 any eq 21
#   deny tcp addrgroup ADDR_GROUP any eq 53
#   permit 1 any any
# Copy *Acl* object
acl2 = acl.copy()
print(acl2.line, "\n")
# ip access-list ACL_NAME
#   permit tcp 10.0.0.0/24 any eq 21
#   permit tcp 10.0.0.0/24 any eq 22
#   permit tcp 10.0.0.0/24 any eq 23
#   deny tcp addrgroup ADDR_GROUP any eq 53
#   permit 1 any any
# Update some data in *Ace* objects
# Note, when iterating *acl2* object, you are iterating list of *Ace* objects in *acl2.items*
acl2.items = [o for o in acl2 if o.srcaddr.line == "10.0.0.0/24"]
for port, ace in enumerate(acl2, start=53):
    ace.protocol.line = "udp"
    ace.dstport.line = f"eq {port}"
acl2.items[1].srcaddr.line = "10.0.1.0/24"
acl2.items[2].srcaddr.line = "10.0.2.0/24"
print(acl2.line, "\n")
# ip access-list ACL_NAME
#   permit udp 10.0.0.0/24 any eq 53
#   permit udp 10.0.1.0/24 any eq 54
#   permit udp 10.0.2.0/24 any eq 55
# Convert from NX-OS extended ACL syntax to IOS standard ACL syntax
acl2.protocol_nr = False
acl2.platform = "ios"
acl2.type = "standard"
print(acl2.line, "\n")
# ip access-list standard ACL_NAME
#   permit 10.0.0.0 0.0.0.255
#   permit 10.0.1.0 0.0.0.255
#   permit 10.0.2.0 0.0.0.255

aces()

cisco_acl.aces(config, platform, group_by) Creates Ace objects based on the “show running-config” output

Parameter

Type

Description

config

str

Cisco config, “show running-config” output

platform

str

Platform: “ios”, “nxos” (default “ios”)

group_by

str

Startswith in remark line. ACEs group, starting from the Remark, where line startswith group_by, will be applied to the same AceGroup, until next Remark that also startswith group_by

Return

List of Ace objects

Examples

./examples/examples_aces.py

from pprint import pprint
import cisco_acl

config = """
permit tcp 10.0.0.0 0.0.0.255 range 1 4 any eq 21 22 23 syn ack log
permit tcp host 10.0.0.1 any eq 21
deny tcp object-group ADDR_GROUP any eq 53
permit icmp any any
"""
# Create list of ACEs
aces = cisco_acl.aces(config=config, platform="ios")
for ace in aces:
    print(f"{ace.line=}")
print()
# ace.line='permit tcp 10.0.0.0 0.0.0.255 range 1 4 any eq ftp 22 telnet syn ack log'
# ace.line='permit tcp host 10.0.0.1 any eq ftp'
# ace.line='deny tcp object-group ADDR_GROUP any eq domain'
# ace.line='permit icmp any any'
# *Ace* some attributes demonstration
ace = aces[0]
print(f"{ace.line=}")
print(f"{ace.platform=}")
print(f"{ace.type=}")
print(f"{ace.sequence=}")
print(f"{ace.action=}")
print(f"{ace.protocol.name=}")
print(f"{ace.protocol.number=}")
print()
print(f"{ace.srcaddr.line=}")
print(f"{ace.srcaddr.addrgroup=}")
print(f"{ace.srcaddr.ipnet=}")
print(f"{ace.srcaddr.prefix=}")
print(f"{ace.srcaddr.subnet=}")
print(f"{ace.srcaddr.wildcard=}")
print()
print(f"{ace.srcport.line=}")
print(f"{ace.srcport.protocol=}")
print(f"{ace.srcport.items=}")
print(f"{ace.srcport.operator=}")
print(f"{ace.srcport.ports=}")
print(f"{ace.srcport.sport=}")
print()
print(f"{ace.dstaddr.line=}")
print(f"{ace.dstaddr.addrgroup=}")
print(f"{ace.dstaddr.ipnet=}")
print(f"{ace.dstaddr.prefix=}")
print(f"{ace.dstaddr.subnet=}")
print(f"{ace.dstaddr.wildcard=}")
print()
print(f"{ace.dstport.line=}")
print(f"{ace.dstport.protocol=}")
print(f"{ace.dstport.items=}")
print(f"{ace.dstport.operator=}")
print(f"{ace.dstport.ports=}")
print(f"{ace.dstport.sport=}")
print()
print(f"{ace.option.line=}")
print(f"{ace.option.flags=}")
print(f"{ace.option.logs=}")
print()
# ace.line='permit tcp 10.0.0.0 0.0.0.255 range 1 4 any eq ftp 22 telnet syn ack log'
# ace.platform='ios'
# ace.type='extended'
# ace.sequence=0
# ace.action='permit'
# ace.protocol.name='tcp'
# ace.protocol.number=6
#
# ace.srcaddr.line='10.0.0.0 0.0.0.255'
# ace.srcaddr.addrgroup=''
# ace.srcaddr.ipnet=IPv4Network('10.0.0.0/24')
# ace.srcaddr.prefix='10.0.0.0/24'
# ace.srcaddr.subnet='10.0.0.0 255.255.255.0'
# ace.srcaddr.wildcard='10.0.0.0 0.0.0.255'
#
# ace.srcport.line='range 1 4'
# ace.srcport.protocol='tcp'
# ace.srcport.items=[1, 4]
# ace.srcport.operator='range'
# ace.srcport.ports=[1, 2, 3, 4]
# ace.srcport.sport='1-4'
#
# ace.dstaddr.line='any'
# ace.dstaddr.addrgroup=''
# ace.dstaddr.ipnet=IPv4Network('0.0.0.0/0')
# ace.dstaddr.prefix='0.0.0.0/0'
# ace.dstaddr.subnet='0.0.0.0 0.0.0.0'
# ace.dstaddr.wildcard='0.0.0.0 255.255.255.255'
#
# ace.dstport.line='eq ftp 22 telnet'
# ace.dstport.protocol='tcp'
# ace.dstport.items=[21, 22, 23]
# ace.dstport.operator='eq'
# ace.dstport.ports=[21, 22, 23]
# ace.dstport.sport='21-23'
#
# ace.option.line='syn ack log'
# ace.option.flags=['syn', 'ack']
# ace.option.logs=['log']
# Convert object to dictionary
data = ace.data()
pprint(data)
print()
# {'line': 'permit tcp 10.0.0.0 0.0.0.255 range 1 4 any eq ftp 22 telnet syn ack log'
#  'platform': 'ios',
#  'action': 'permit',
#  'srcaddr': {'addrgroup': '',
#              'ipnet': IPv4Network('10.0.0.0/24'),
#              'line': '10.0.0.0 0.0.0.255',
#              'prefix': '10.0.0.0/24',
#              'subnet': '10.0.0.0 255.255.255.0',
#              'type': 'wildcard',
#              'wildcard': '10.0.0.0 0.0.0.255'},
#  'srcport': {'items': [1, 4],
#              'line': 'range 1 4',
#              'operator': 'range',
#              'ports': [1, 2, 3, 4],
#              'protocol': 'tcp',
#              'sport': '1-4'},
# ...
# Copy *Ace* object
ace2 = ace.copy()
print(f"{ace2.line=}", "\n")
# ace2.line='permit tcp 10.0.0.0 0.0.0.255 range 1 4 any eq ftp 22 telnet syn ack log'

addrgroups()

cisco_acl.addrgroups(config, platform) Creates AddrGroup objects based on the “show running-config” output

Parameter

Type

Description

config

str

Cisco config, “show running-config” output

platform

str

Platform: “ios”, “nxos” (default “ios”)

Return

List of AddrGroup objects

range_ports()

cisco_acl.range_ports(srcports, dstports, line, platform, port_nr) Generates ACEs in required range of TCP/UDP source/destination ports

Parameter

Type

Description

srcports

str

Range of TCP/UDP source ports

dstports

str

Range of TCP/UDP destination ports

line

str

ACE pattern, on whose basis new ACEs will be generated (default “permit tcp any any”, operator “eq”)

platform

str

Platform: “ios”, “nxos” (default “ios”)

port_nr

bool

Well-known TCP/UDP ports as numbers, True - all tcp/udp ports as numbers, False - well-known tcp/udp ports as names (default)

Return

List of newly generated ACE lines

Examples

./examples/examples_range_ports.py

from pprint import pprint
import cisco_acl

# Generate range of source TCP ports
aces = cisco_acl.range_ports(srcports="21-23,80")
pprint(aces)
print()
# ['permit tcp any eq ftp any',
#  'permit tcp any eq 22 any',
#  'permit tcp any eq telnet any',
#  'permit tcp any eq www any']
# Generate range of destination TCP ports
aces = cisco_acl.range_ports(dstports="21-23,80")
pprint(aces)
print()
# ['permit tcp any any eq ftp',
#  'permit tcp any any eq 22',
#  'permit tcp any any eq telnet',
#  'permit tcp any any eq www']
# Generate range where well-known TCP ports represented as numbers
aces = cisco_acl.range_ports(dstports="21-23,80", port_nr=True)
pprint(aces)
print()
# ['permit tcp any any eq 21',
#  'permit tcp any any eq 22',
#  'permit tcp any any eq 23',
#  'permit tcp any any eq 80']
# Generate range of UDP ports based on the template with specified address
aces = cisco_acl.range_ports(dstports="53,67-68,123", line="deny udp host 10.0.0.1 any eq 1")
pprint(aces)
print()
# ['deny udp host 10.0.0.1 any eq domain',
#  'deny udp host 10.0.0.1 any eq bootps',
#  'deny udp host 10.0.0.1 any eq bootpc',
#  'deny udp host 10.0.0.1 any eq ntp']

range_protocols()

cisco_acl.range_protocols(protocols, line, platform, protocol_nr) Generates ACEs in required range of IP protocols

Parameter

Type

Description

protocols

str

Range of IP protocols

line

str

ACE pattern, on whose basis new ACEs will be generated (default “permit ip any any”)

platform

str

Platform: “ios”, “nxos” (default “ios”)

protocol_nr

bool

Well-known ip protocols as numbers, True - all ip protocols as numbers, False - well-known ip protocols as names (default)

Return

List of newly generated ACE lines

Examples

./examples/examples_range_protocols.py

from pprint import pprint
import cisco_acl

# Generate range of IP protocols
aces = cisco_acl.range_protocols(protocols="1-3,6,17")
pprint(aces)
print()
# ['permit icmp any any',
#  'permit igmp any any',
#  'permit 3 any any',
#  'permit tcp any any',
#  'permit udp any any']
# Generate range where well-known IP protocols represented as numbers
aces = cisco_acl.range_protocols(protocols="1-3,6,17", protocol_nr=True)
pprint(aces)
print()
# ['permit 1 any any',
#  'permit 2 any any',
#  'permit 3 any any',
#  'permit 6 any any',
#  'permit 17 any any']

Objects

Additional documentation for deep divers

./docs/objects.rst

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cisco_acl-2.1.0.tar.gz (49.7 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page