# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
# All Rights Reserved.
#
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import collections
import netaddr
import six
if ports:
return None
"""Driver which enforces security groups through PF rules.
Please look at neutron.agent.firewall.FirewallDriver for more information
on how the methods below are called from the Neutron Open vSwitch agent. It
all starts at prepare_port_filter() and then _setup_pf_rules() has all the
PF based logic to add correct rules on guest instance's port.
"""
# List of port which has security group
self.filtered_ports = {}
self.unfiltered_ports = {}
# List of security group rules for ports residing on this host
# List of security group member ips for ports residing on this host
# Every PF rule needs to be labeled so that we can later kill the state
# associated with that rule (using pfctl -k label -k 110). It is hard
# to come up with a meaningfully named label for each PF rule, so we
# are resorting to numbers here.
self.portid_to_devname = {}
"""We never call this method
It exists here to override abstract method of parent abstract class.
"""
pass
(sg_id, sg_members))
device_ids=None):
# TODO(gmoodalb): Extend this later to optimize handling of security
# groups update
pass
if not device_name:
return
# we need to remove both ingress and egress
if '/' in device_name:
else:
ingress = 'in'
egress = 'out'
(ingress, device_name))
(egress, device_name))
else:
else:
if update:
if '/' in device_name:
return device_name
ipv4_sg_rules = []
ipv6_sg_rules = []
for rule in security_group_rules:
return ipv4_sg_rules, ipv6_sg_rules
return [rule
# Fixed rules for traffic sourced from unspecified addresses: 0.0.0.0
# and ::
# Allow dhcp client discovery and request
'to 255.255.255.255/32 port 67 label "%s"' %
# Allow neighbor solicitation and multicast listener discovery
# from the unspecified address for duplicate address detection
'from ::/128 to ff02::/16 icmp6-type %s '
# Fixed rules for traffic after source address is verified
# Allow dhcp client renewal and rebinding
'label "%s"' % (device_name,
# Drop Router Advts from the port.
'icmp6-type %s label "%s"' %
# Allow IPv6 ICMP traffic
# Allow IPv6 DHCP Client traffic
'to port 547 label "%s"' %
# Drop dhcp packet from VM
'to port 68 label "%s"' %
'from port 547 to port 546 label "%s"' %
# Allow multicast listener, neighbor solicitation and
# neighbor advertisement into the instance
'icmp6-type %s label "%s"' %
"""Select rules from the security groups the port is member of."""
port_rules = []
for sg_id in port_sg_ids:
return port_rules
"""Expand a remote group rule to rule per remote group IP."""
if remote_group_id:
yield ip_rule
else:
yield rule
if remote_sg_id and ether_type:
return remote_sg_ids
if '/' in device_name:
else:
else:
# self.pf.add_nested_anchor_rule(None, anchor_name, anchor_option)
''' Add a generic block everything rule. The default security group
in OpenStack adds 'pass all egress traffic' and prevents all the
incoming traffic'''
if not device_name:
return
# select rules for current port and direction
# split groups by ip version
# for ipv4, 'pass' will be used
# for ipv6, 'pass inet6' will be used
ipv4_pf_rules = []
ipv6_pf_rules = []
# include IPv4 and IPv6 iptable rules from security group
if protocol:
if port_range_min is None:
return
if port_range_min == port_range_max:
else:
if port_range_max is not None:
if ip_prefix != 'any':
if '/' not in ip_prefix:
# we need to convert it into a cidr
ip_prefix = 'any'
else:
pf_rules = []
for sg_rule in security_group_rules:
pf_rule = ['pass']
else:
return pf_rules