Python package to parse and manage Cisco ACL (Access Control List)
Project description
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
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
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.