def main(): """Entry point.""" options = parse() setup_logging(options.debug, options.silent, options.name, options.syslog_facility, not options.no_syslog) if options.pid: options.pid.write("{0}\n".format(os.getpid())) options.pid.close() try: # Setup IP to use options.ips = options.ips or loopback_ips(options.label, False) if not options.ips: logger.error("No IP found") sys.exit(1) if options.ip_setup: setup_ips(options.ips, options.label, options.sudo) drop_privileges(options.user, options.group) # Parse defined networks into a list of IPs for advertisement if options.deaggregate_networks: options.ips = [ip_network(ip) for net in options.ips for ip in net] options.ips = collections.deque(options.ips) options.ips.rotate(-options.start_ip) options.ips = list(options.ips) # Main loop loop(options) except Exception as e: # pylint: disable=W0703 logger.exception("Uncaught exception: %s", e) sys.exit(1)
def loopback_ips(label, label_only): """Retrieve loopback IP addresses""" logger.debug("Retrieve loopback IP addresses") addresses = [] if sys.platform.startswith("linux"): # Use "ip" (ifconfig is not able to see all addresses) ipre = re.compile(r"^(?P<index>\d+):\s+(?P<name>\S+)\s+inet6?\s+" r"(?P<ip>[\da-f.:]+)/(?P<mask>\d+)\s+.*") labelre = re.compile(r".*\s+lo:(?P<label>\S+).*") cmd = subprocess.Popen("/sbin/ip -o address show dev lo".split(), shell=False, stdout=subprocess.PIPE) else: # Try with ifconfig ipre = re.compile(r"^inet6?\s+(alias\s+)?(?P<ip>[\da-f.:]+)\s+" r"(?:netmask 0x(?P<netmask>[0-9a-f]+)|" r"prefixlen (?P<mask>\d+)).*") cmd = subprocess.Popen("/sbin/ifconfig lo0".split(), shell=False, stdout=subprocess.PIPE) labelre = re.compile(r"") for line in cmd.stdout: line = line.decode("ascii", "ignore").strip() mo = ipre.match(line) if not mo: continue if mo.group("mask"): mask = int(mo.group("mask")) else: mask = bin(int(mo.group("netmask"), 16)).count("1") try: ip = ip_network("{0}/{1}".format(mo.group("ip"), mask)) except ValueError: continue if not ip.is_loopback: if label: lmo = labelre.match(line) if not lmo: continue if lmo.groupdict().get("label", "").startswith(label): addresses.append(ip) elif not label_only: addresses.append(ip) logger.debug("Loopback addresses: %s", addresses) return addresses
def remove_ips(ips, label, sudo=False): """Remove added IP on loopback interface""" existing = set(loopback_ips(label, True)) # Get intersection of IPs (ips setup, and IPs configured by ExaBGP) toremove = set([ip_network(ip) for net in ips for ip in net]) & existing for ip in toremove: logger.debug("Remove loopback IP address %s", ip) with open(os.devnull, "w") as fnull: cmd = ["ip", "address", "delete", str(ip), "dev", loopback()] if sudo: cmd.insert(0, "sudo") if label: cmd += ["label", "{0}:{1}".format(loopback(), label)] try: subprocess.check_call(cmd, stdout=fnull, stderr=fnull) except subprocess.CalledProcessError: logger.warn( "Unable to remove loopback IP address %s - is \ healthcheck running as root?", str(ip))
def setup_ips(ips, label, sudo=False): """Setup missing IP on loopback interface""" existing = set(loopback_ips(label, False)) toadd = set([ip_network(ip) for net in ips for ip in net]) - existing for ip in toadd: logger.debug("Setup loopback IP address %s", ip) with open(os.devnull, "w") as fnull: cmd = ["ip", "address", "add", str(ip), "dev", loopback()] if sudo: cmd.insert(0, "sudo") if label: cmd += ["label", "{0}:{1}".format(loopback(), label)] try: subprocess.check_call(cmd, stdout=fnull, stderr=fnull) except subprocess.CalledProcessError as e: # the IP address is already setup, ignoring if cmd[0] == "ip" and cmd[2] == "add" and e.returncode == 2: continue raise e