Vendor Galaxy Roles and Collections
This commit is contained in:
parent
c1e1897cda
commit
2aed20393f
3553 changed files with 387444 additions and 2 deletions
19
ansible_collections/debops/debops/roles/dhcp_probe/COPYRIGHT
Normal file
19
ansible_collections/debops/debops/roles/dhcp_probe/COPYRIGHT
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
debops.dhcp_probe - Configure DHCP Probe using Ansible
|
||||
|
||||
Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _dhcp_probe__ref_defaults:
|
||||
|
||||
# debops.dhcp_probe default variables
|
||||
# ===================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# APT packages [[[
|
||||
# ----------------
|
||||
|
||||
# .. envvar:: dhcp_probe__base_packages [[[
|
||||
#
|
||||
# List of APT packages required for DHCP Probe service.
|
||||
dhcp_probe__base_packages: [ 'dhcp-probe' ]
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__packages [[[
|
||||
#
|
||||
# List of additional APT packages to install with DHCP Probe.
|
||||
dhcp_probe__packages: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Custom directories, scripts [[[
|
||||
# -------------------------------
|
||||
|
||||
# .. envvar:: dhcp_probe__cache [[[
|
||||
#
|
||||
# Absolute path of the cache directory where :command:`mail-throttled` script
|
||||
# state is stored.
|
||||
dhcp_probe__cache: '{{ (ansible_local.fhs.cache | d("/var/cache"))
|
||||
+ "/dhcp-probe" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__lib [[[
|
||||
#
|
||||
# Absolute path where the custom scripts used by the DHCP Probe service are
|
||||
# stored.
|
||||
dhcp_probe__lib: '{{ (ansible_local.fhs.lib | d("/usr/local/lib"))
|
||||
+ "/dhcp-probe" }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Monitored network interfaces [[[
|
||||
# --------------------------------
|
||||
|
||||
# These variables define on which network interfaces DHCP Probe will listen for
|
||||
# rogue DHCP servers. By default Ethernet interfaces, bridges, VLAN interfaces,
|
||||
# bonds and various uplink interfaces with IPv4 addresses will be monitored.
|
||||
# See :ref:`dhcp_probe__ref_interfaces` for more details.
|
||||
|
||||
# .. envvar:: dhcp_probe__default_interfaces [[[
|
||||
#
|
||||
# List of default network interfaces to listen on for rogue DHCP servers.
|
||||
dhcp_probe__default_interfaces: '{{ lookup("template", "lookup/dhcp_probe__default_interfaces.j2",
|
||||
convert_data=False) | from_yaml }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__interfaces [[[
|
||||
#
|
||||
# Additional list of network interfaces to listen on for rogue DHCP servers.
|
||||
dhcp_probe__interfaces: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__combined_interfaces [[[
|
||||
#
|
||||
# The variable that combines the interface lists and is used in the role tasks.
|
||||
dhcp_probe__combined_interfaces: '{{ dhcp_probe__default_interfaces
|
||||
+ dhcp_probe__interfaces }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# DHCP Probe configuration [[[
|
||||
# ----------------------------
|
||||
|
||||
# .. envvar:: dhcp_probe__alert_program [[[
|
||||
#
|
||||
# Absolute path of the script executed by DHCP Probe when new rogue DHCP server
|
||||
# is detected. By default an e-mail message will be generated and sent to the
|
||||
# system administrator. Set to an empty string to disable.
|
||||
dhcp_probe__alert_program: '{{ dhcp_probe__lib + "/dhcp_probe_notify2" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__legal_servers [[[
|
||||
#
|
||||
# List of IPv4 addresses of the DHCP servers that are allowed on the network.
|
||||
# If both an IP address list and a hardware address list are specified, both
|
||||
# elements must match.
|
||||
dhcp_probe__legal_servers: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__legal_servers_ethersrc [[[
|
||||
#
|
||||
# List of hardware (MAC) addresses of the DHCP servers that are allowed on the
|
||||
# network. If both an IP address list and a hardware address list are
|
||||
# specified, both elements must match.
|
||||
dhcp_probe__legal_servers_ethersrc: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__options [[[
|
||||
#
|
||||
# A string or YAML text block with custom :command:`dhcp_probe` options.
|
||||
# See :man:`dhcp_probe.cf(5)` for more details about available options.
|
||||
dhcp_probe__options: ''
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Mail and pager notification [[[
|
||||
# -------------------------------
|
||||
|
||||
# These variables are used to configure the custom mail notification script
|
||||
# used by DHCP Probe to notify the system administrator about rogue DHCP
|
||||
# servers found on the network.
|
||||
|
||||
# .. envvar:: dhcp_probe__domain [[[
|
||||
#
|
||||
# The DNS domain used to send e-mail notifications about rogue DHCP servers.
|
||||
dhcp_probe__domain: '{{ ansible_domain }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__mail_from [[[
|
||||
#
|
||||
# The sender of the notification mail. The default ``root`` will be expanded to
|
||||
# a full e-mail address by the SMTP server.
|
||||
dhcp_probe__mail_from: 'root'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__mail_to [[[
|
||||
#
|
||||
# The list of the e-mail addresses of recipients which should get the
|
||||
# notification mail.
|
||||
dhcp_probe__mail_to: [ 'root@{{ dhcp_probe__domain }}' ]
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__mail_subject [[[
|
||||
#
|
||||
# The prefix of the notification mail subject.
|
||||
dhcp_probe__mail_subject: 'Unexpected BOOTP/DHCP server'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__mail_timeout [[[
|
||||
#
|
||||
# Time in seconds between successive notification mail messages.
|
||||
dhcp_probe__mail_timeout: '{{ 20 * 60 }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__page_to [[[
|
||||
#
|
||||
# The list of e-mail addresses of recipients which will receive short e-mail
|
||||
# messages, suitable for pagers.
|
||||
dhcp_probe__page_to: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: dhcp_probe__page_timeout [[[
|
||||
#
|
||||
# Time in seconds between successive notification pager messages.
|
||||
dhcp_probe__page_timeout: '{{ 20 * 60 }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski'
|
||||
description: 'Configure DHCP Probe service'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.6.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions:
|
||||
- bionic
|
||||
|
||||
- name: 'Debian'
|
||||
versions:
|
||||
- stretch
|
||||
- buster
|
||||
|
||||
galaxy_tags:
|
||||
- dhcp
|
||||
- networking
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import custom Ansible plugins
|
||||
ansible.builtin.import_role:
|
||||
name: 'ansible_plugins'
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
- name: Install required packages
|
||||
ansible.builtin.package:
|
||||
name: '{{ q("flattened", (dhcp_probe__base_packages + dhcp_probe__packages)) }}'
|
||||
state: 'present'
|
||||
register: dhcp_probe__register_packages
|
||||
until: dhcp_probe__register_packages is succeeded
|
||||
|
||||
- name: Ensure that sysvinit dhcp-probe service is stopped on install
|
||||
ansible.builtin.systemd:
|
||||
name: 'dhcp-probe.service'
|
||||
state: 'stopped'
|
||||
when: ((ansible_local is undefined or
|
||||
ansible_local.dhcp_probe is undefined) and
|
||||
ansible_service_mgr == 'systemd')
|
||||
|
||||
- name: Install custom systemd unit files
|
||||
ansible.builtin.template:
|
||||
src: 'etc/systemd/system/{{ item }}.j2'
|
||||
dest: '/etc/systemd/system/{{ item }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
loop: [ 'dhcp-probe@.service', 'dhcp-probe.service' ]
|
||||
notify: [ 'Reload service manager' ]
|
||||
when: ansible_service_mgr == 'systemd'
|
||||
|
||||
- name: Reload systemd configuration when needed
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
||||
- name: Disable DHCP Probe instances if requested
|
||||
ansible.builtin.systemd:
|
||||
name: 'dhcp-probe@{{ item.name }}.service'
|
||||
state: 'stopped'
|
||||
enabled: False
|
||||
loop: '{{ dhcp_probe__combined_interfaces | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state} }}'
|
||||
when: ansible_service_mgr == 'systemd' and item.name | d() and
|
||||
item.state | d('present') == 'absent'
|
||||
|
||||
- name: Enable DHCP Probe instances if requested
|
||||
ansible.builtin.systemd:
|
||||
name: 'dhcp-probe@{{ item.name }}.service'
|
||||
enabled: True
|
||||
loop: '{{ dhcp_probe__combined_interfaces | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state} }}'
|
||||
when: ansible_service_mgr == 'systemd' and item.name | d() and
|
||||
item.state | d('present') != 'absent'
|
||||
notify: [ 'Restart dhcp-probe' ]
|
||||
|
||||
- name: Ensure that required directories exist
|
||||
ansible.builtin.file:
|
||||
path: '{{ item }}'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
loop: [ '{{ dhcp_probe__cache }}', '{{ dhcp_probe__lib }}' ]
|
||||
|
||||
- name: Install custom notification scripts
|
||||
ansible.builtin.template:
|
||||
src: 'usr/local/lib/dhcp-probe/{{ item }}.j2'
|
||||
dest: '{{ dhcp_probe__lib + "/" + item }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
loop: [ 'dhcp_probe_notify2', 'mail-throttled' ]
|
||||
|
||||
- name: Generate dhcp_probe.cf configuration file
|
||||
ansible.builtin.template:
|
||||
src: 'etc/dhcp_probe.cf.j2'
|
||||
dest: '/etc/dhcp_probe.cf'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
notify: [ 'Restart dhcp-probe' ]
|
||||
|
||||
- name: Make sure Ansible fact directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
|
||||
- name: Setup DHCP Probe local facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/dhcp_probe.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/dhcp_probe.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
notify: [ 'Refresh host facts' ]
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Reload facts if they were modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps
|
||||
import os
|
||||
|
||||
|
||||
def cmd_exists(cmd):
|
||||
return any(
|
||||
os.access(os.path.join(path, cmd), os.X_OK)
|
||||
for path in os.environ["PATH"].split(os.pathsep)
|
||||
)
|
||||
|
||||
|
||||
output = {'installed': cmd_exists('/usr/sbin/dhcp_probe')}
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if dhcp_probe__alert_program | d() %}
|
||||
# Send mail messages about unauthorized DHCP servers
|
||||
alert_program_name2 {{ dhcp_probe__alert_program }}
|
||||
{% endif %}
|
||||
{% if dhcp_probe__legal_servers | d() %}
|
||||
|
||||
# List of IP addresses of legal DHCP servers
|
||||
{% for address in ([ dhcp_probe__legal_servers ] if dhcp_probe__legal_servers is string else dhcp_probe__legal_servers) %}
|
||||
legal_server {{ address }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if dhcp_probe__legal_servers_ethersrc | d() %}
|
||||
|
||||
# List of MAC addresses of legal DHCP servers
|
||||
{% for address in ([ dhcp_probe__legal_servers_ethersrc ] if dhcp_probe__legal_servers_ethersrc is string else dhcp_probe__legal_servers_ethersrc) %}
|
||||
legal_server_ethersrc {{ address }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if dhcp_probe__options | d() %}
|
||||
|
||||
# Custom options
|
||||
{{ dhcp_probe__options }}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[Unit]
|
||||
Description=Daemon to survery DHCP/BOOTP servers on LAN
|
||||
After=network-online.target
|
||||
Documentation=man:dhcp_probe(8)
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/true
|
||||
ExecReload=/bin/true
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
{# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[Unit]
|
||||
Description=Daemon to survey DHCP/BOOTP servers on LAN
|
||||
After=network-online.target
|
||||
Documentation=man:dhcp_probe(8)
|
||||
ConditionPathExists=/etc/dhcp_probe.cf
|
||||
PartOf=dhcp-probe.service
|
||||
ReloadPropagatedFrom=dhcp-probe.service
|
||||
Before=dhcp-probe.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
Slice=system-dhcp-probe.slice
|
||||
ExecStart=/usr/sbin/dhcp_probe -T -p /var/run/dhcp-probe/dhcp_probe.%i.pid %i
|
||||
|
||||
PIDFile=/var/run/dhcp-probe/dhcp_probe.%i.pid
|
||||
|
||||
# dhcp_probe ignores SIGTERM
|
||||
KillMode=control-group
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
RuntimeDirectory=dhcp-probe
|
||||
RuntimeDirectoryMode=0755
|
||||
|
||||
PrivateTmp=yes
|
||||
LimitNOFILE=65535
|
||||
PrivateDevices=yes
|
||||
ProtectHome=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=dhcp-probe.service
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
{% set dhcp_probe__tpl_interfaces = [] %}
|
||||
{% for element in ansible_interfaces %}
|
||||
{% if element.startswith(('bond', 'br', 'en', 'eth', 'mesh', 'sit', 'sl', 'tap', 'tun', 'vlan', 'wl', 'ww')) %}
|
||||
{% if hostvars[inventory_hostname]['ansible_' + element]['ipv4'] is defined %}
|
||||
{% set _ = dhcp_probe__tpl_interfaces.append({
|
||||
'name': element,
|
||||
'state': 'present'
|
||||
}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ dhcp_probe__tpl_interfaces | to_yaml }}
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Copyright (C) 2008 Irwin Tillman <networking@princeton.edu>
|
||||
# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: BSD-4-Clause
|
||||
|
||||
|
||||
# dhcp_probe was created by the Network Systems Group at Princeton University's
|
||||
# Office of Information Technology, networking at princeton dot edu.
|
||||
# It was written by Irwin Tillman.
|
||||
#
|
||||
# Portions of this software are copyrighted by other organizations or individuals;
|
||||
# see below for details one which portions, and what legal notices apply
|
||||
# to each of those portions.
|
||||
#
|
||||
# Those portions of the software which have not identified below as copyrighted
|
||||
# by other organizations or individuals are themselves Copyright (©) 2000-2008,
|
||||
# The Trustees of Princeton University, All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary form, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * The redistribution, use, or modification shall not violate any of the additional
|
||||
# copyrights, patents, or other restrictions below.
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# * If redistribution includes any portion of the software that is copyrighted by other
|
||||
# organizations or individuals (as detailed below), the copyright notice associated with
|
||||
# that portion of the software also must be retained.
|
||||
#
|
||||
# * Neither the names of the individual authors or contributos, nor the
|
||||
# name of "Princeton University" may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# This software is provided "as is" and any express or implied
|
||||
# warranties, including, but not limited to, the implied warranties of
|
||||
# mechantability and fitness for a particular purpose are disclaimed. In
|
||||
# no event shall the authors or Princeton University be liable for any
|
||||
# direct, indirect, incidental, special exemplary, or consequential
|
||||
# damages (including, but not limited to, procurement of substitute goods
|
||||
# or services; loss of use, data, or profits; or business interruption)
|
||||
# however caused and on any theory of liability, whether in contract,
|
||||
# strict liability, or tort (including negligence or otherwise) arising
|
||||
# in any way out of the use of this software, even if advised of the
|
||||
# possibility of such damage.
|
||||
|
||||
|
||||
# dhcp_probe_notify2 -p calling_prog_name -I interface_name -i IPaddress -m MACaddress [-y yiaddr]
|
||||
#
|
||||
# An external program called by dhcp_probe upon response of a response from an unexpected BootP/DHCP server.
|
||||
#
|
||||
# Called via specification of 'alert_program_name2' in /etc/dhcp_probe.cf file.
|
||||
# This version obeys the syntax provided by the 'alert_program_name2' statement,
|
||||
# not the syntax provided by the older 'alert_program_name' statement.
|
||||
#
|
||||
# Required options:
|
||||
# -p calling_prog_name the name of the calling program (e.g. 'dhcp_probe')
|
||||
# -I interface_name the name of the interface on which the unexpected response packet arrived (e.g. 'qfe0')
|
||||
# -i IPaddress the IP source address of the unexpected response packet (e.g. '192.168.0.1')
|
||||
# -m MACaddress the Ethernet source address of the unexpected response packet (e.g. '0:1:2:3:4:5')
|
||||
#
|
||||
# Optional options:
|
||||
# -y yiaddr the response packet's non-zero yiaddr value, when it falls within a "Lease Network of Interest" (e.g. '172.16.1.2')
|
||||
#
|
||||
# May send email subject to throttling.
|
||||
# May send page subject to throttling.
|
||||
#
|
||||
# You will need to edit the definitions below.
|
||||
#
|
||||
# Irwin Tillman
|
||||
|
||||
|
||||
use Sys::Hostname;
|
||||
use Sys::Syslog qw(:DEFAULT setlogsock);
|
||||
use Time::HiRes qw(gettimeofday); # from CPAN
|
||||
use Getopt::Std;
|
||||
use strict;
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Definitions you may need to edit
|
||||
|
||||
my $SYSLOG_FACILITY="daemon"; # name of facility to use if syslogging (e.g. 'daemon')
|
||||
my $SYSLOG_OPT = 'pid,cons'; # comma-separated syslog options to use if syslogging (e.g. 'pid,cons') , ignored if not syslogging
|
||||
|
||||
use vars qw($VERBOSE);
|
||||
$VERBOSE = 1; # set to true to produce more verbose messages
|
||||
|
||||
# We may send one piece of mail this way, subject to frequency throttling.
|
||||
# Use this set of definitions for a piece of email that is delivered as regular email (not a page).
|
||||
use vars qw($THROTTLE_MAIL_CMD $THROTTLE_MAIL_TIMEOUT $THROTTLE_MAIL_FROM $THROTTLE_MAIL_RECIPIENT $THROTTLE_MAIL_RECIPIENT_TEST $THROTTLE_MAIL_SUBJECT);
|
||||
{% if dhcp_probe__mail_to | d() %}
|
||||
$THROTTLE_MAIL_CMD = "{{ dhcp_probe__lib + '/mail-throttled' }}"; # set to "" to disable
|
||||
{% else %}
|
||||
$THROTTLE_MAIL_CMD = ""; # set to "" to disable
|
||||
{% endif %}
|
||||
$THROTTLE_MAIL_TIMEOUT = {{ dhcp_probe__mail_timeout | default('600') }}; # seconds
|
||||
$THROTTLE_MAIL_FROM = "{{ dhcp_probe__mail_from | replace('@', '\@') }}"; # e.g. "root"
|
||||
$THROTTLE_MAIL_RECIPIENT = "{{ dhcp_probe__mail_to | join(' ') | replace('@','\@') }}"; # space-separated email addresses, remember to escape '@' characters
|
||||
$THROTTLE_MAIL_SUBJECT = "{{ dhcp_probe__mail_subject }}";
|
||||
|
||||
|
||||
# We may also send another piece of email this way, subject to frequency throttling.
|
||||
# Use this set of definitions for a piece of email that is delivered to a pager (not as regular email).
|
||||
use vars qw($THROTTLE_PAGE_CMD $THROTTLE_PAGE_TIMEOUT $THROTTLE_PAGE_RECIPIENT);
|
||||
{% if dhcp_probe__page_to | d() %}
|
||||
$THROTTLE_PAGE_CMD = "{{ dhcp_probe__lib + '/mail-throttled' }}"; # set to "" to disable
|
||||
{% else %}
|
||||
$THROTTLE_PAGE_CMD = ""; # set to "" to disable
|
||||
{% endif %}
|
||||
$THROTTLE_PAGE_TIMEOUT = {{ dhcp_probe__page_timeout | default('600') }}; # seconds
|
||||
$THROTTLE_PAGE_RECIPIENT = "{{ dhcp_probe__page_to | join(' ') | replace('@','\@') }}"; # space-separated email addresses, remember to escape '@' characters
|
||||
|
||||
|
||||
# End of definitions you may need to edit
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
(my $prog = $0) =~ s/.*\///;
|
||||
|
||||
# init our use of syslog
|
||||
# setlogsock('unix'); # talk to syslog with UNIX domain socket, not INET domain. XXX causes failure in Solaris 7
|
||||
openlog($prog, $SYSLOG_OPT, $SYSLOG_FACILITY);
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Parse options and arguments
|
||||
|
||||
# We must use getopt() instead of getopts() to avoid throwing an error
|
||||
# if we are passed an unrecognized option.
|
||||
# We must silently ignore unrecognized options to be forward compatible with enhancements to dhcp_probe.
|
||||
use vars qw($opt_i $opt_I $opt_m $opt_p $opt_y);
|
||||
# &getopt('p:i:I:m:y:');
|
||||
&getopt('piImy');
|
||||
|
||||
# Required options
|
||||
my $calling_program = $opt_p;
|
||||
my $ifname = $opt_I;
|
||||
my $ip_src = $opt_i;
|
||||
my $ether_src = $opt_m;
|
||||
#
|
||||
# Optional options
|
||||
my $yiaddr = $opt_y || "";
|
||||
|
||||
|
||||
# Enforce presence of required options
|
||||
unless ($calling_program) {
|
||||
my_message('LOG_ERR', "${prog}: missing -p calling_program option");
|
||||
exit 100;
|
||||
}
|
||||
unless ($ifname) {
|
||||
my_message('LOG_ERR', "${prog}: missing -I interface_name option");
|
||||
exit 101;
|
||||
}
|
||||
unless ($ip_src) {
|
||||
my_message('LOG_ERR', "${prog}: missing -i ip_src_address option");
|
||||
exit 102;
|
||||
}
|
||||
unless ($ether_src) {
|
||||
my_message('LOG_ERR', "${prog}: missing -m ether_src_address option");
|
||||
exit 103;
|
||||
}
|
||||
|
||||
# Done parsing options and arguments
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
# Miscellaneous Initialization
|
||||
|
||||
my $hostname = hostname();
|
||||
|
||||
my ($seconds, $microseconds) = gettimeofday; # from Time::HiRes on CPAN
|
||||
my $timestamp = scalar(localtime($seconds));
|
||||
$timestamp =~ s/(\d\d:\d\d:\d\d)/$1.$microseconds/; # glue microsends to end of seconds
|
||||
|
||||
|
||||
|
||||
# When we pass a key to THROTTLE_MAIL_CMD, we want the key to also include an indication
|
||||
# of whether the yiaddr option was specified. (If we didn't include such an indication,
|
||||
# the following could happen: The first response we detect from a rogue server doesn't
|
||||
# distribute an "address of concern", so the yiaddr option wasn't specified. We alert
|
||||
# based on that. The next response we detect from a rogue server does distribute an
|
||||
# "address of concern", so the yiaddr is specified. Our alert gets throttled since
|
||||
# the first alert we sent was "recent". But this means the administrator doesn't get
|
||||
# notified that the rogue distributed an "address of interest". So we need to
|
||||
# include the state of yiaddr option in the key we pass to THROTTLE_MAIL_CMD,
|
||||
# to ensure the second response isn't throttled using the same key as the first response.)
|
||||
#
|
||||
# We can't just use the value of yiaddr itself as the string to incorporate into the key,
|
||||
# as that would result in a unique key for each distributed IP address. Instead, we
|
||||
# will use the state of yiaddr (set or unset).
|
||||
#
|
||||
# Note this means that when a rogue DHCP server is distributing IP addresses that fall into "Networks of Concern",
|
||||
# we will very likely send more than one notification for it within each throttle period.
|
||||
# That's because while some of the responses from the rogue will have a yiaddr within a "Networks of Concern",
|
||||
# others (for example, DHCPNAK responses) will not. This is unfortunate, but is better than the
|
||||
# alternative approach (of not taking into account the yiaddr state in the key), since that will
|
||||
# sometimes cause you to not be alerted at all to the "yiaddr falls into a Network of Concern" situation.
|
||||
#
|
||||
# Create a string based on the state of yiaddr, for later incorporation into the key.
|
||||
my $yiaddr_option_state = $yiaddr ? "yiaddr=set" : "yiaddr=unset";
|
||||
|
||||
#############################################################################
|
||||
|
||||
if ($THROTTLE_MAIL_CMD) {
|
||||
# This command suppresses the message if it's sent a message to 'key' within 'throttle_seconds'
|
||||
# I use the calling program's name and the offender's hardware address as the key.
|
||||
|
||||
my $subject_yiaddr_addendum = "";
|
||||
$subject_yiaddr_addendum = ", YIADDR=$yiaddr" if $yiaddr;
|
||||
|
||||
unless (open(THROTTLE_MAIL, "| $THROTTLE_MAIL_CMD -l -k ${calling_program}_mail_${ether_src}_$yiaddr_option_state -t $THROTTLE_MAIL_TIMEOUT -f \"$THROTTLE_MAIL_FROM\" -r \"$THROTTLE_MAIL_RECIPIENT\" -s\"$THROTTLE_MAIL_SUBJECT (MAC=${ether_src}, IP=${ip_src}${subject_yiaddr_addendum})\"")) {
|
||||
|
||||
my_message('LOG_ERR', "${prog}: failure trying to send throttled email: can't execute '${THROTTLE_MAIL_CMD}': open(): $!");
|
||||
exit 20;
|
||||
}
|
||||
|
||||
print THROTTLE_MAIL
|
||||
$timestamp, "\n",
|
||||
"\n",
|
||||
"$calling_program detected an unexpected BOOTP/DHCP server.\n",
|
||||
"Host=$hostname, interface=${ifname}, IP source=${ip_src}, Ethernet source=${ether_src}\n";
|
||||
print THROTTLE_MAIL "\nThis means that *there is* a rogue BOOTP/DHCP server operating.\n" if $VERBOSE;
|
||||
if ($yiaddr) {
|
||||
print THROTTLE_MAIL
|
||||
"The server distributed IP address $yiaddr, which falls into a network of special concern.\n";
|
||||
}
|
||||
|
||||
unless (close(THROTTLE_MAIL)) {
|
||||
my_message('LOG_ERR',
|
||||
"${prog}: failure trying to send throttled email: error executing '${THROTTLE_MAIL_CMD}': close(): " .
|
||||
($! ?
|
||||
"syserr closing pipe: $!"
|
||||
:
|
||||
"wait status $? from pipe"
|
||||
) .
|
||||
"\n"
|
||||
);
|
||||
exit 21;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if ($THROTTLE_PAGE_CMD) {
|
||||
# This command suppresses the message if it's sent a message to 'key' within 'throttle_seconds'
|
||||
# I use the calling program's name and the offender's hardware address as the key.
|
||||
|
||||
unless (open(THROTTLE_PAGE, "| $THROTTLE_PAGE_CMD -l -k ${calling_program}_page_${ether_src}_$yiaddr_option_state -t $THROTTLE_PAGE_TIMEOUT -r \"$THROTTLE_PAGE_RECIPIENT\"")) {
|
||||
my_message('LOG_ERR', "${prog}: failure trying to send throttled page: can't execute '${THROTTLE_PAGE_CMD}': open(): $!\n");
|
||||
exit 30;
|
||||
}
|
||||
|
||||
print THROTTLE_PAGE "Rogue DHCP server IP=$ip_src MAC=$ether_src seen via host $hostname interface $ifname\n";
|
||||
print THROTTLE_PAGE "This means *there is* a rogue BOOTP/DHCP server operating.\n" if $VERBOSE;
|
||||
if ($yiaddr) {
|
||||
print THROTTLE_PAGE
|
||||
"Rogue server distributed yiaddr=$yiaddr, a special concern.\n";
|
||||
}
|
||||
|
||||
unless (close(THROTTLE_PAGE)) {
|
||||
my_message('LOG_ERR',
|
||||
"${prog}: failure trying to send throttled page: error executing '${THROTTLE_PAGE_CMD}': close(): " .
|
||||
($! ?
|
||||
"syserr closing pipe: $!"
|
||||
:
|
||||
"wait status $? from pipe"
|
||||
) .
|
||||
"\n"
|
||||
);
|
||||
exit 31;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
#############################################################################
|
||||
|
||||
sub my_message {
|
||||
# Call with a syslog priority constant and a message string.
|
||||
# We write the message to syslog, using the specified priority.
|
||||
# Your message should not contain a newline.
|
||||
|
||||
my($priority, $msg) = @_;
|
||||
syslog($priority, $msg);
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Copyright (C) 2008 Irwin Tillman <networking@princeton.edu>
|
||||
# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: BSD-4-Clause
|
||||
|
||||
|
||||
# dhcp_probe was created by the Network Systems Group at Princeton University's
|
||||
# Office of Information Technology, networking at princeton dot edu.
|
||||
# It was written by Irwin Tillman.
|
||||
#
|
||||
# Portions of this software are copyrighted by other organizations or individuals;
|
||||
# see below for details one which portions, and what legal notices apply
|
||||
# to each of those portions.
|
||||
#
|
||||
# Those portions of the software which have not identified below as copyrighted
|
||||
# by other organizations or individuals are themselves Copyright (©) 2000-2008,
|
||||
# The Trustees of Princeton University, All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary form, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * The redistribution, use, or modification shall not violate any of the additional
|
||||
# copyrights, patents, or other restrictions below.
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# * If redistribution includes any portion of the software that is copyrighted by other
|
||||
# organizations or individuals (as detailed below), the copyright notice associated with
|
||||
# that portion of the software also must be retained.
|
||||
#
|
||||
# * Neither the names of the individual authors or contributos, nor the
|
||||
# name of "Princeton University" may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# This software is provided "as is" and any express or implied
|
||||
# warranties, including, but not limited to, the implied warranties of
|
||||
# mechantability and fitness for a particular purpose are disclaimed. In
|
||||
# no event shall the authors or Princeton University be liable for any
|
||||
# direct, indirect, incidental, special exemplary, or consequential
|
||||
# damages (including, but not limited to, procurement of substitute goods
|
||||
# or services; loss of use, data, or profits; or business interruption)
|
||||
# however caused and on any theory of liability, whether in contract,
|
||||
# strict liability, or tort (including negligence or otherwise) arising
|
||||
# in any way out of the use of this software, even if advised of the
|
||||
# possibility of such damage.
|
||||
|
||||
|
||||
# $Header: /usr/local/etc/RCS/mail-throttled,v 1.11 2008/12/06 01:50:28 root Exp $
|
||||
|
||||
# mail-throttled [-l] [-D dbm_file] -k key -t throttle_seconds [-f from] -r recipient [-d] [-T tie_attempts_max] [-S tie_retry_sleep] [-s subject]
|
||||
#
|
||||
# Sends mail body (read from STDIN) to 'recipient', but avoids doing so "too frequently."
|
||||
#
|
||||
# You provide a 'key', which is an arbitrary string used to identify this notification.
|
||||
# You also provide 'throttle_seconds', an integer. If we've sent anything that
|
||||
# specified this 'key' within the last 'throttle_seconds', we do not send the message.
|
||||
# Otherwise, we send the message, and the remember that we've sent a message for this 'key'
|
||||
# at the current time.
|
||||
#
|
||||
# This key/timesent tuples are stored on-disk, in a dbm. As a result, the 'key'
|
||||
# you supply must satisfy the syntactic requirements for dbm keys.
|
||||
# The caller needs to have permission to read and write this DBM (and create it if
|
||||
# it does not already exist). If you fail to specify a dbm_file, we'll use a default
|
||||
# value, which may not be what you want (since the caller might not be able to r/w that
|
||||
# particular DBM).
|
||||
# We never clean this dbm. You can safely erase it entirely, if you don't mind losing
|
||||
# the state, and you know the caller has permission to create a new instance of the DBM.
|
||||
#
|
||||
# The 'recipient' should be a valid email address. Naturally, it should not
|
||||
# be one that will cause any ack or bounce mail to return to us!
|
||||
# If there are several addresses (delimited by spaces), be sure to quote them as a single arg.
|
||||
#
|
||||
# If a subject is specified, be sure to quote it if it contains any spaces or other shell
|
||||
# metachars.
|
||||
#
|
||||
# If -l is specified, then any errors, warnings, or debugging output is written to syslog
|
||||
# in addition to its usual destination (STDERR). This is helpful if you call this from an
|
||||
# environment where STDERR may get lost.
|
||||
#
|
||||
# Irwin Tillman
|
||||
|
||||
use Getopt::Std;
|
||||
use GDBM_File;
|
||||
use Errno qw(EAGAIN);
|
||||
use Sys::Syslog qw(:DEFAULT setlogsock);
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use vars qw($DBM_FILE_DEFAULT $MAILCMD $MAILCMD_OPTS $FROM_DEFAULT);
|
||||
$DBM_FILE_DEFAULT = '{{ dhcp_probe__cache + "/mail-throttled.gdbm" }}';
|
||||
$MAILCMD = "/usr/lib/sendmail";
|
||||
# $MAILCMD_OPTS = "-t -ODeliveryMode=queueonly";
|
||||
$MAILCMD_OPTS = "-t";
|
||||
$FROM_DEFAULT = "root";
|
||||
|
||||
my $SYSLOG_FACILITY="daemon"; # name of facility to use if syslogging
|
||||
my $SYSLOG_OPT = 'pid,cons'; # syslog options to use if syslogging, ignored otherwise
|
||||
my $SYSLOG_PRIORITY = 'LOG_ERR';
|
||||
|
||||
# The tie() call sometimes fails with EAGAIN.
|
||||
# Perhaps that's due to some other process having the DBM open;
|
||||
# in fact, that may be more likely if the process that calls us may calls us multiple times in quick succession.
|
||||
# So when tie() fails with EAGAIN, we can sleep and retry some number of times before giving up entirely.
|
||||
my $TIE_ATTEMPTS_MAX = 3; # number of times to try tie() before giving up
|
||||
my $TIE_RETRY_SLEEP = 1; # seconds to sleep before retrying tie()
|
||||
|
||||
(my $prog = $0) =~ s/.*\///;
|
||||
|
||||
use vars qw($opt_f $opt_D $opt_d $opt_k $opt_l $opt_r $opt_s $opt_S $opt_t $opt_T);
|
||||
&getopts('dD:f:k:lr:s:S:t:T:');
|
||||
|
||||
my $debug = $opt_d || "";
|
||||
my $dbm_file = $opt_D || $DBM_FILE_DEFAULT;
|
||||
my $key = $opt_k || "";
|
||||
my $from = $opt_f || $FROM_DEFAULT;
|
||||
my $recipient = $opt_r || "";
|
||||
my $throttle_secs = $opt_t || 1;
|
||||
my $subject = $opt_s || "";
|
||||
my $also_syslog = $opt_l || "";
|
||||
my $tie_attempts_max = $opt_T || $TIE_ATTEMPTS_MAX; # we deliberately override if CLI option specifies 0, as that makes no sense
|
||||
my $tie_retry_sleep = $opt_S || $TIE_RETRY_SLEEP;
|
||||
|
||||
if ($also_syslog) {
|
||||
# init our use of syslog
|
||||
# setlogsock('unix'); # talk to syslog with UNIX domain socket, not INET domain. XXX causes failure in Solaris 7
|
||||
openlog($prog, $SYSLOG_OPT, $SYSLOG_FACILITY);
|
||||
}
|
||||
|
||||
my_warn("${prog}:\nkey=$key\nthrottle_secs=$throttle_secs\nfrom=$from\nrecipient=$recipient\ntie_attempts_max=$tie_attempts_max\ntie_retry_sleep=$tie_retry_sleep\nsubject=$subject") if $debug;
|
||||
|
||||
# certain options and args are required
|
||||
&Usage() unless ($key && $throttle_secs && $recipient);
|
||||
|
||||
my %last_sent = ();
|
||||
my $tie_succeeded = 0;
|
||||
my $tie_attempts_left = $TIE_ATTEMPTS_MAX;
|
||||
|
||||
while ($tie_attempts_left--) {
|
||||
if (tie(%last_sent, 'GDBM_File', $dbm_file, &GDBM_WRCREAT, 0644)) {
|
||||
$tie_succeeded = 1;
|
||||
last;
|
||||
}
|
||||
# the tie() failed
|
||||
|
||||
if ($! == EAGAIN) {
|
||||
# The failure may be due to a transient problem.
|
||||
# Retrying may help.
|
||||
sleep $TIE_RETRY_SLEEP;
|
||||
next;
|
||||
|
||||
} else {
|
||||
# Some other (presumably more serious) error.
|
||||
last;
|
||||
}
|
||||
}
|
||||
unless ($tie_succeeded) {
|
||||
my_warn("${prog}: can't tie ${dbm_file}: $!");
|
||||
exit 10;
|
||||
}
|
||||
|
||||
my @mailbody = "";
|
||||
@mailbody = <STDIN>; # read it even if we decide not to send it
|
||||
|
||||
my $now = time;
|
||||
|
||||
my_warn("now = $now") if $debug;
|
||||
|
||||
$last_sent{$key} = 0 unless defined($last_sent{$key}); # so it's defined before we use it in subtraction (placate use strict)
|
||||
|
||||
if ($now - $last_sent{$key} >= $throttle_secs) {
|
||||
my_warn("last_sent = $last_sent{$key}, will send") if $debug;
|
||||
unless (open(MAIL, "| $MAILCMD $MAILCMD_OPTS -f\"$from\"")) {
|
||||
my_warn("${prog}: error executing '${MAILCMD}': open(): $!");
|
||||
exit 20;
|
||||
}
|
||||
print MAIL "From: $from\n",
|
||||
"To: $recipient\n",
|
||||
($subject ? "Subject: $subject\n" : "") ,
|
||||
"\n",
|
||||
@mailbody;
|
||||
unless (close(MAIL)) {
|
||||
my_warn("${prog}: error executing '${MAILCMD}': close(): " .
|
||||
($! ?
|
||||
"syserror closing pipe: $!"
|
||||
:
|
||||
"wait status $? from pipe"
|
||||
)
|
||||
);
|
||||
exit 21;
|
||||
}
|
||||
|
||||
$last_sent{$key} = $now;
|
||||
} else {
|
||||
my_warn("last_sent = $last_sent{$key}, suppressing") if $debug;
|
||||
}
|
||||
|
||||
untie %last_sent;
|
||||
|
||||
exit 0;
|
||||
|
||||
|
||||
|
||||
sub Usage {
|
||||
my_warn("Usage: $prog [-l] [-D dbm_file] -k key -t throttle_seconds [-f from] -r recipient [-T tie_attempts_max] [-S tie_retry_sleep] [-s subject]");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
sub my_warn {
|
||||
# Just a wrapper for warn, but with a possible copy to syslog too.
|
||||
my $msg = shift;
|
||||
warn $msg, "\n";
|
||||
syslog($SYSLOG_PRIORITY, $msg) if $also_syslog;
|
||||
return;
|
||||
}
|
||||
Loading…
Reference in a new issue