Validate rogue DHCP servers

This adds two validations that check for unexpected DHCP servers in the
networks used for hardware introspection and provisioning.

Both validations depend on a file that sends a DHCP request for each
interface specified in its arguments and fails if there are any
responses.

Closes-Bug: #1620332
Change-Id: I22d4bf31e8f528e345b1a0a3ec972beea13d4f52
This commit is contained in:
Tomas Sedovic 2016-08-11 12:42:42 +02:00
parent 2445041593
commit 0a608f83bd
3 changed files with 111 additions and 0 deletions

View File

@ -0,0 +1,25 @@
---
- hosts: undercloud
become: true
vars:
metadata:
name: DHCP on the Introspection Network
description: >
An unexpected DHCP server on the network used for node
introspection can cause some nodes to not be inspected.
This validations checks for the DHCP responses on the
interface specified in ironic-inspector.conf.
groups:
- pre-introspection
tasks:
- name: Install scapy
pip: name=scapy state=present virtualenv=/tmp/validations-venv
- name: Look up the introspection interface
ini: path=/etc/ironic-inspector/inspector.conf section=firewall key=dnsmasq_interface
register: interface
- name: Look up the introspection interface from the deprecated option
ini: path=/etc/ironic-inspector/inspector.conf section=discoverd key=dnsmasq_interface
register: interface_deprecated
- name: Look for rogue DHCP servers
script: files/rogue_dhcp.py {{ interface.value or interface_deprecated.value or 'br-ctlplane' }}

View File

@ -0,0 +1,24 @@
---
- hosts: undercloud
become: true
vars:
metadata:
name: DHCP on the Provisioning Network
description: >
An unexpected DHCP server on the provisioning network can
cause problems with deploying the Ironic nodes.
This validation checks for DHCP responses on the undercloud's
provisioning interface (eth1 by default) and fails if there
are any.
groups:
- pre-deployment
tasks:
- name: Get the path of tripleo undercloud config file
hiera: name="tripleo_undercloud_conf_file"
- name: Gather undercloud.conf values
undercloud_conf: undercloud_conf_path={{ tripleo_undercloud_conf_file }}
- name: Install scapy
pip: name=scapy state=present virtualenv=/tmp/validations-venv
- name: Look for DHCP responses
script: files/rogue_dhcp.py {{ undercloud_conf.DEFAULT.local_interface|default('eth1') }}

View File

@ -0,0 +1,62 @@
#!/tmp/validations-venv/bin/python
# -*- coding: utf-8 -*-
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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.
# Disable scapy's warning to stderr:
import logging
import sys
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import BOOTP
from scapy.all import conf
from scapy.all import DHCP
from scapy.all import Ether
from scapy.all import get_if_raw_hwaddr
from scapy.all import IP
from scapy.all import srp
from scapy.all import UDP
def find_dhcp_servers(timeout_sec, interface):
conf.checkIPaddr = False
fam, hw = get_if_raw_hwaddr(interface)
dhcp_discover = (Ether(dst="ff:ff:ff:ff:ff:ff") /
IP(src="0.0.0.0", dst="255.255.255.255") /
UDP(sport=68, dport=67) /
BOOTP(chaddr=hw) /
DHCP(options=[("message-type", "discover"), "end"]))
ans, unans = srp(dhcp_discover, multi=True,
timeout=timeout_sec, verbose=False)
return [(unicode(packet[1][IP].src), packet[1][Ether].src)
for packet in ans]
def main():
dhcp_servers = []
for interface in sys.argv[1:]:
dhcp_servers.extend(find_dhcp_servers(30, interface))
if dhcp_servers:
sys.stderr.write('Found {} DHCP servers:'.format(len(dhcp_servers)))
for ip, mac in dhcp_servers:
sys.stderr.write("\n* {} ({})".format(ip, mac))
sys.exit(1)
else:
print("No DHCP servers found.")
if __name__ == '__main__':
main()