Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[caclmgrd] Add some default ACCEPT rules and lastly drop all incoming packets #4412

Merged
merged 6 commits into from
May 11, 2020
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 140 additions & 7 deletions files/image_config/caclmgrd/caclmgrd
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#

try:
import ipaddr as ipaddress
import ipaddress
import os
import subprocess
import sys
Expand Down Expand Up @@ -61,12 +61,21 @@ class ControlPlaneAclManager(object):

ACL_TABLE_TYPE_CTRLPLANE = "CTRLPLANE"

# To specify a port range, use iptables format: separate start and end
# ports with a colon, e.g., "1000:2000"
# To specify a port range instead of a single port, use iptables format:
# separate start and end ports with a colon, e.g., "1000:2000"
ACL_SERVICES = {
"NTP": {"ip_protocols": ["udp"], "dst_ports": ["123"]},
"SNMP": {"ip_protocols": ["tcp", "udp"], "dst_ports": ["161"]},
"SSH": {"ip_protocols": ["tcp"], "dst_ports": ["22"]}
"NTP": {
"ip_protocols": ["udp"],
"dst_ports": ["123"]
},
"SNMP": {
"ip_protocols": ["tcp", "udp"],
"dst_ports": ["161"]
},
"SSH": {
"ip_protocols": ["tcp"],
"dst_ports": ["22"]
lguohan marked this conversation as resolved.
Show resolved Hide resolved
}
}

def __init__(self):
Expand Down Expand Up @@ -115,6 +124,73 @@ class ControlPlaneAclManager(object):
tcp_flags_str = tcp_flags_str[:-1]
return tcp_flags_str

def generate_block_ip2me_traffic_iptables_commands(self):
LOOPBACK_INTERFACE_TABLE = "LOOPBACK_INTERFACE"
MGMT_INTERFACE_TABLE = "MGMT_INTERFACE"
VLAN_INTERFACE_TABLE = "VLAN_INTERFACE"
PORTCHANNEL_INTERFACE_TABLE = "PORTCHANNEL_INTERFACE"
INTERFACE_TABLE = "INTERFACE"

block_ip2me_cmds = []

# Add iptables rules to drop all packets destined for loopback interface IP addresses
loopback_iface_table = self.config_db.get_table(LOOPBACK_INTERFACE_TABLE)
for ((iface_name, iface_cidr), _) in loopback_iface_table.iteritems():
ip_ntwrk = ipaddress.ip_network(iface_cidr, strict=False)
if isinstance(ip_ntwrk, ipaddress.IPv4Network):
block_ip2me_cmds.append("iptables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
elif isinstance(ip_ntwrk, ipaddress.IPv6Network):
block_ip2me_cmds.append("ip6tables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
else:
log_warning("Unrecognized IP address type on interface '{}': {}".format(iface_name, ip_ntwrk))

# Add iptables rules to drop all packets destined for management interface IP addresses
mgmt_iface_table = self.config_db.get_table(MGMT_INTERFACE_TABLE)
for ((iface_name, iface_cidr), _) in mgmt_iface_table.iteritems():
ip_ntwrk = ipaddress.ip_network(iface_cidr, strict=False)
if isinstance(ip_ntwrk, ipaddress.IPv4Network):
block_ip2me_cmds.append("iptables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
elif isinstance(ip_ntwrk, ipaddress.IPv6Network):
block_ip2me_cmds.append("ip6tables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
else:
log_warning("Unrecognized IP address type on interface '{}': {}".format(iface_name, ip_ntwrk))

# Add iptables rules to drop all packets destined for our VLAN interface gateway IP addresses
vlan_iface_table = self.config_db.get_table(VLAN_INTERFACE_TABLE)
for ((iface_name, iface_cidr), _) in vlan_iface_table.iteritems():
ip_ntwrk = ipaddress.ip_network(iface_cidr, strict=False)
if isinstance(ip_ntwrk, ipaddress.IPv4Network):
block_ip2me_cmds.append("iptables -A INPUT -d {}/{} -j DROP".format(list(ip_ntwrk.hosts())[0], ip_ntwrk.max_prefixlen))
elif isinstance(ip_ntwrk, ipaddress.IPv6Network):
block_ip2me_cmds.append("ip6tables -A INPUT -d {}/{} -j DROP".format(list(ip_ntwrk.hosts())[0], ip_ntwrk.max_prefixlen))
else:
log_warning("Unrecognized IP address type on interface '{}': {}".format(iface_name, ip_ntwrk))

# Add iptables rules to drop all packets destined for point-to-point interface IP addresses
# (All portchannel interfaces and configured front-panel interfaces)
portchannel_iface_table = self.config_db.get_table(PORTCHANNEL_INTERFACE_TABLE)
for ((iface_name, iface_cidr), _) in portchannel_iface_table.iteritems():
ip_ntwrk = ipaddress.ip_network(iface_cidr, strict=False)
if isinstance(ip_ntwrk, ipaddress.IPv4Network):
block_ip2me_cmds.append("iptables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
elif isinstance(ip_ntwrk, ipaddress.IPv6Network):
block_ip2me_cmds.append("ip6tables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
else:
log_warning("Unrecognized IP address type on interface '{}': {}".format(iface_name, ip_ntwrk))

iface_table = self.config_db.get_table(INTERFACE_TABLE)
for ((iface_name, iface_cidr), _) in iface_table.iteritems():
ip_ntwrk = ipaddress.ip_network(iface_cidr, strict=False)
if isinstance(ip_ntwrk, ipaddress.IPv4Network):
block_ip2me_cmds.append("iptables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
elif isinstance(ip_ntwrk, ipaddress.IPv6Network):
block_ip2me_cmds.append("ip6tables -A INPUT -d {}/{} -j DROP".format(ip_ntwrk.network_address, ip_ntwrk.max_prefixlen))
else:
log_warning("Unrecognized IP address type on interface '{}': {}".format(iface_name, ip_ntwrk))

return block_ip2me_cmds


def get_acl_rules_and_translate_to_iptables_commands(self):
"""
Retrieves current ACL tables and rules from Config DB, translates
Expand Down Expand Up @@ -147,14 +223,54 @@ class ControlPlaneAclManager(object):
iptables_cmds.append("ip6tables -F")
iptables_cmds.append("ip6tables -X")

# Add iptables commands to allow all IPv4 and IPv6 traffic from localhost
# Add iptables/ip6tables commands to allow all traffic from localhost
iptables_cmds.append("iptables -A INPUT -s 127.0.0.1 -i lo -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -s ::1 -i lo -j ACCEPT")

# Add iptables/ip6tables commands to allow all incoming packets from established
# TCP sessions or new TCP sessions which are related to established TCP sessions
iptables_cmds.append("iptables -A INPUT -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT")

# Add iptables/ip6tables commands to allow bidirectional ICMPv4 ping and traceroute
# TODO: Support processing ICMPv4 service ACL rules, and remove this blanket acceptance
iptables_cmds.append("iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT")
iptables_cmds.append("iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT")

# Add iptables/ip6tables commands to allow bidirectional ICMPv6 ping and traceroute
# TODO: Support processing ICMPv6 service ACL rules, and remove this blanket acceptance
iptables_cmds.append("ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT")

# Add iptables/ip6tables commands to allow all incoming Neighbor Discovery Protocol (NDP) NS/NA/RS/RA messages
# TODO: Support processing NDP service ACL rules, and remove this blanket acceptance
iptables_cmds.append("ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT")

# Add iptables/ip6tables commands to allow all incoming IPv4 DHCP packets
iptables_cmds.append("iptables -A INPUT -p udp --dport 67:68 --sport 67:68 -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p udp --dport 67:68 --sport 67:68 -j ACCEPT")

# Add iptables/ip6tables commands to allow all incoming IPv6 DHCP packets
iptables_cmds.append("iptables -A INPUT -p udp --dport 546:547 --sport 546:547 -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p udp --dport 546:547 --sport 546:547 -j ACCEPT")

# Add iptables/ip6tables commands to allow all incoming BGP traffic
# TODO: Determine BGP ACLs based on configured device sessions, and remove this blanket acceptance
iptables_cmds.append("iptables -A INPUT -p tcp --dport 179 -j ACCEPT")
iptables_cmds.append("iptables -A INPUT -p tcp --sport 179 -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p tcp --dport 179 -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p tcp --sport 179 -j ACCEPT")


# Get current ACL tables and rules from Config DB
self._tables_db_info = self.config_db.get_table(self.ACL_TABLE)
self._rules_db_info = self.config_db.get_table(self.ACL_RULE)

num_ctrl_plane_acl_rules = 0

# Walk the ACL tables
for (table_name, table_data) in self._tables_db_info.iteritems():

Expand Down Expand Up @@ -246,6 +362,23 @@ class ControlPlaneAclManager(object):
rule_cmd += " -j {}".format(rule_props["PACKET_ACTION"])

iptables_cmds.append(rule_cmd)
num_ctrl_plane_acl_rules += 1

# Add iptables commands to block ip2me traffic
iptables_cmds += self.generate_block_ip2me_traffic_iptables_commands()

# Add iptables/ip6tables commands to allow all incoming packets with TTL of 0 or 1
# This allows the device to respond to tools like tcptraceroute
iptables_cmds.append("iptables -A INPUT -m ttl --ttl-lt 2 -j ACCEPT")
iptables_cmds.append("ip6tables -A INPUT -p tcp -m hl --hl-lt 2 -j ACCEPT")

# Finally, if the device has control plane ACLs configured,
# add iptables/ip6tables commands to drop all other incoming packets
if num_ctrl_plane_acl_rules > 0:
iptables_cmds.append("iptables -A INPUT -j DROP")
iptables_cmds.append("iptables -A FORWARD -j DROP")
iptables_cmds.append("ip6tables -A INPUT -j DROP")
iptables_cmds.append("ip6tables -A FORWARD -j DROP")

return iptables_cmds

Expand Down