2020-04-03
再谈cuckoo与suricata

再谈cuckoo与suricata suricata到底可以做哪些工作?再谈cuckoo与suricatasuricata 与cuckoo可以有机的进行结合。suricata还原的文件可以给cuckoo使用,cuckoo中恶意文件产生的数据流量报文,可以反过来给suricata回放规则检测。二者可以有机进行...

Read More
 2020-04-03
docker学习记录


docker的网络模式

当你开始大规模使用Docker时,你会发现需要了解很多关于网络的知识。Docker作为目前最火的轻量级容器技术,有很多令人称道的功能,如Docker的镜像管理。然而,Docker同样有着很多不完善的地方,网络方面就是Docker比较薄弱的部分。因此,我们有必要深入了解Docker的网络知识,以满足更高的网络需求。本文首先介绍了Docker自身的4种网络工作方式,然后介绍一些自定义网络模式。

安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host

模式 简介 备注
host模式 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口 优势:性能高,适用于对网络效率有较高要求,但是对于端口会于宿主机冲突
bridge模式 此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信 拥有独立隔离的网络
none模式 该模式关闭了容器的网络功能,挂在这个网络下的容器除了 lo,没有其他任何网卡 在保密闭环的空间中使用,一般不使用
Container模式 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。 两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
自定义网络模式 Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建跨主机的网络 docker network create -d bridge –subnet 172.25.0.0/16 network_name

docker-host网络

11585881740_.pic_hd.jpg

docker-bridge网络

docker默认的网络连接方式为bridge,即桥接模式。在实际运行中会生成一个虚拟的网桥docker0,这边的虚拟网桥就类似于物理交换机的作用,而veth则可以类比物理交换机的端口 ,veth与容器内的eth0网卡 就是一队veth-pair,关于veth-pair技术可以参考该链接Linux-虚拟网络设备-veth pair,. 而docker0作为linux普通网桥,可以配置ip,这样便可以在三层进行网络通讯了。 20170828171704363.png

Docker 创建一个容器的时候,会执行如下操作:

  • 创建一对虚拟接口/网卡,也就是veth pair,分别放到本地主机和新容器中;
  • 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 vetha596da4;
  • 容器一端放到新容器中,并修改名字作为 eth0,这个网卡/接口只在容器的名字空间可见;
  • 从网桥可用地址段中(也就是与该bridge对应的network)获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 vetha596da4。
  • 完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。
  • 如果不指定–network,创建的容器默认都会挂到 docker0 上,使用本地主机上 docker0 接口的 IP 作为所有容器的默认网关。

iptables

ipforward

我们知道bridge模式下,会生成虚拟docker0,docker0为容器的默认网关。作为容器与外界通讯的媒介,docker0 与宿主机的网卡如何通讯呢? 这边其实就利用了linux多网卡数据包的转发功能。

Linux系统默认多网卡之间的数据包转发功能是关闭的。开启方法如下: 数据包转发功能默认配置 cat /proc/sys/net/ipv4/ip_forward 0 设置为1的时候转发 开机自动数据包转发 把下面代码添加到开机启动项/etc/rc.d/rc.local echo “1″ >/proc/sys/net/ipv4/ip_forward 或者修改/etc/sysctl.conf net.ipv4.ip_forward = 1

docker常见问题解答

Q:docker build的时候需要连接外网,但是有时候连接不上,为什么如何解决?

A: docker build 默认采用bridge模式,该方式需要桥接网卡,但是没看到。所以采用host 模式进行 docker build --network=host -t test . 参考:https://www.debugself.com/2018/01/17/docker_network/

附录

  1. docker容器的网络配置
  2. docker-compose配置ipv6

Read More
 2020-04-02
Python3实现Http中间件

背景介绍

项目需要编写一个中间件,对面提供Http接口,首先肯定想到的就是对 基于python3的简易http-server进行改造。 但是项目实际过程中,中间件的调用可能来自多方,多个用户都会对这个接口进行异步的调用,所以该接口就需要对异步的调用进行及时的处理。

ps: 直接运行的话可以 python3 -m http.server

框架选择

首先可以想到的是http-server框架与flask框架。

  • 首先联想到cuckoo-agent模块,agent.py。 他是基于python2的SimpleHTTPServer实现的。对其并发性能没有深入研究,不过该agent主要部署在虚拟机中,同时也只会处理一个任务。
  • http-server比较简单,而flask则是python实现web服务器的通用框架。不管http-server、flask都是一个轻量级别的服务。
  • 对于并发请求http-server,它可以有多个连接,但是同时只能处理一条请求任务。该方式就一定会产生阻塞。一开始想的是利用 超时函数,超过固定的秒数就直接返回,但是该方式在多用户的情况下,不是一个很好的选择。
  • 对于flask 实现http服务,很显然更快捷,但是你会发现一些问题,就是你同一条指令、同一浏览器重复请求,会出现阻塞情况。尽管使用了多线程。 可以参考该连接:python flask如何解决同时请求同一个请求的阻塞问题?。当然也有解决方法,不过先入为主了。

因此,问题就变为了,如何处理http-server的并发问题: 后来也找到了解决方式 就是使用ThreadingMixIn,参考python3 HttpServer 实现多线程

代码demo

http-server 基于flask demo


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 参考: https://www.cnblogs.com/liangqihui/p/9139270.html
from flask import Flask, abort, request, jsonify

app = Flask(__name__)

# 测试数据暂时存放
tasks = []

@app.route('/add_task/', methods=['POST'])
def add_task():
    if not request.json or 'id' not in request.json or 'info' not in request.json:
        abort(400)
    task = {
        'id': request.json['id'],
        'info': request.json['info']
    }
    tasks.append(task)
    return jsonify({'result': 'success'})


@app.route('/get_task/', methods=['GET'])
def get_task():
    if not request.args or 'id' not in request.args:
        # 没有指定id则返回全部
        return jsonify(tasks)
    else:
        task_id = request.args['id']
        task = filter(lambda t: t['id'] == int(task_id), tasks)
        return jsonify(task) if task else jsonify({'result': 'not found'})


if __name__ == "__main__":
    # 将host设置为0.0.0.0,则外网用户也可以访问到这个服务
    app.run(host="0.0.0.0", port=8383, debug=True)

http-server 基于http.server demo

这边用到了一个装饰器,用于判断函数运行超时,返回信息。

from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import subprocess
import os
import time
from threading import Timer
import getpass
import logging
import os.path
import sys
import signal
import codecs
# from signal import signal, SIGPIPE, SIG_DFL


sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())

data = {'result': 'this is a agent!!'}
# 监听主机 & 端口
host = ('0.0.0.0', 4322)
# gvm指令请求超时时间,单位秒
gvm_order_timeout = 6


class Node():
    def __init__(self):
        self.connect_method = ""  # 连接方法
        self.host_name = "127.0.0.1"  # 主机名如:127.0.0.1


def timeout_exception():
    return (500, "run_gvm deal timeout")


def set_timeout(num, callback):
    def wrape(func):
        def handle(signum, frame):
            raise ("运行超时")

        def toDo(*args, **kwargs):
            try:
                signal.signal(signal.SIGALRM, handle)
                signal.alarm(num)  # 开启闹钟信号
                rs = func(*args, **kwargs)
                signal.alarm(0)  # 关闭闹钟信号
                return rs
            except:
                callback()

        return toDo

    return wrape


class Resquest(BaseHTTPRequestHandler):
    timeout = 10
    hostname = '127.0.0.1'
    port = 9390
    username = ''
    password = ''

    def handler(self, code, response):
        self.send_response(code)
        self.send_header('Content-type', 'application/txt')
        self.end_headers()
        self.wfile.write(response.encode())

    def timeout_callback(self, p):
        print('exe time out call back')
        print(p.id)
        try:
            p.kill()
        except Exception as error:
            print(error)

    def run_cmd(self, cmd):
        print('running:%s' % cmd)
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=os.getcwd(), shell=True)
        my_timer = Timer(self.timeout, self.timeout_callback, [p])
        my_timer.start()
        try:
            print("start to count timeout; timeout set to be %d \n" % (self.timeout,))
            out, stderr = p.communicate()
            # exit_code = p.returncode
        finally:
            my_timer.cancel()
            return out.decode()

    @set_timeout(gvm_order_timeout, timeout_exception)
    def run_app(self, node):
        return 200, "Parameters are missing"

    def do_GET(self):
        print(self.requestline)
        if self.path != '/hello':
            self.handler(404, "Parameters are missing")
            return
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps(data).encode())

    def do_POST(self):
        # print(self.headers)
        # print(self.command)
        # print(self.path, len(self.path), type(self.path))
        if self.headers['Referer'] != 'localHost':
            self.handler(404, "Parameters are missing")
            return
        if self.path == '/':
            self.path = '/tls'
        if self.path != '/tls' and self.path != '/ssh' and self.path != '/sock':
            self.handler(405, "Request method error")
            return
        # 读取请求体内容
        req_datas = self.rfile.read(int(self.headers['content-length']))
        # print(req_datas.decode())
        node = Node()
        node.gvm_cmd = req_datas.decode()
        node.host_name = self.headers['host_name']

        code, data = self.run_app(node)
        data_len = len(data)
        if data_len == 0 or data == "":
            self.handler(405, "response is null")
            return

        self.send_response(code)
        self.send_header('Content-type', 'application/xml')
        self.end_headers()
        # 返回信息量大 需分批写
        offset = 0
        n = data_len % 1024
        m = int(data_len / 1024)
        # print(data_len, m , n)
        for i in range(m):
            data_tmp = data[offset: offset + 1024]
            offset = offset + 1024
            self.wfile.write(data_tmp.encode())
        data_tmp = data[offset:]
        self.wfile.write(data_tmp.encode())


# 可以多线程,多队列的方式,
if __name__ == '__main__':
    server = HTTPServer(host, Resquest)
    server.timeout = 10
    print("Starting server, listen at: %s:%s" % host)
    # server.serve_forever()
    while True:
        server.handle_request()

http-server 基于ThreadingMixIn实现多线程处理:


from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import subprocess
import os
import time
from threading import Timer
import getpass
import logging
import os.path
import sys
import signal
import codecs
from socketserver import ThreadingMixIn
# from signal import signal, SIGPIPE, SIG_DFL


sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())

data = {'result': 'this is a agent!!'}
# 监听主机 & 端口
host = ('0.0.0.0', 4322)
# gvm指令请求超时时间,单位秒
gvm_order_timeout = 6


class Node():
    def __init__(self):
        self.connect_method = ""  # 连接方法
        self.host_name = "127.0.0.1"  # 主机名如:127.0.0.1


def timeout_exception():
    return (500, "run_gvm deal timeout")


def set_timeout(num, callback):
    def wrape(func):
        def handle(signum, frame):
            raise ("运行超时")

        def toDo(*args, **kwargs):
            try:
                signal.signal(signal.SIGALRM, handle)
                signal.alarm(num)  # 开启闹钟信号
                rs = func(*args, **kwargs)
                signal.alarm(0)  # 关闭闹钟信号
                return rs
            except:
                callback()

        return toDo

    return wrape


class Resquest(BaseHTTPRequestHandler):
    timeout = 10
    hostname = '127.0.0.1'
    port = 9390
    username = ''
    password = ''

    def handler(self, code, response):
        self.send_response(code)
        self.send_header('Content-type', 'application/txt')
        self.end_headers()
        self.wfile.write(response.encode())

    def timeout_callback(self, p):
        print('exe time out call back')
        print(p.id)
        try:
            p.kill()
        except Exception as error:
            print(error)

    def run_cmd(self, cmd):
        print('running:%s' % cmd)
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=os.getcwd(), shell=True)
        my_timer = Timer(self.timeout, self.timeout_callback, [p])
        my_timer.start()
        try:
            print("start to count timeout; timeout set to be %d \n" % (self.timeout,))
            out, stderr = p.communicate()
            # exit_code = p.returncode
        finally:
            my_timer.cancel()
            return out.decode()

    def run_app(self, node):
        print("demo1111")
        time.sleep(10)
        return 200, "Parameters are missing"

    def do_GET(self):
        print(self.requestline)
        if self.path != '/hello':
            self.handler(404, "Parameters are missing")
            return
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps(data).encode())

    def do_POST(self):
        # print(self.headers)
        # print(self.command)
        # print(self.path, len(self.path), type(self.path))
        if self.headers['Referer'] != 'localHost':
            self.handler(404, "Parameters are missing")
            return
        if self.path == '/':
            self.path = '/tls'
        if self.path != '/tls' and self.path != '/ssh' and self.path != '/sock':
            self.handler(405, "Request method error")
            return
        # 读取请求体内容
        req_datas = self.rfile.read(int(self.headers['content-length']))
        # print(req_datas.decode())
        node = Node()
        node.gvm_cmd = req_datas.decode()
        node.host_name = self.headers['host_name']

        code, data = self.run_app(node)
        data_len = len(data)
        if data_len == 0 or data == "":
            self.handler(405, "response is null")
            return

        self.send_response(code)
        self.send_header('Content-type', 'application/xml')
        self.end_headers()
        # 返回信息量大 需分批写
        offset = 0
        n = data_len % 1024
        m = int(data_len / 1024)
        # print(data_len, m , n)
        for i in range(m):
            data_tmp = data[offset: offset + 1024]
            offset = offset + 1024
            self.wfile.write(data_tmp.encode())
        data_tmp = data[offset:]
        self.wfile.write(data_tmp.encode())

class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
    pass

# 可以多线程,多队列的方式,
if __name__ == '__main__':
    #server = HTTPServer(host, Resquest)
    server = ThreadingHttpServer(host, Resquest)
    server.timeout = 10
    print("Starting server, listen at: %s:%s" % host)
    server.serve_forever()
    

client

	
import  requests

url = 'http://10.25.40.30:4321'
header = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
          'Accept': 'text / html,application / xml',
          'Referer': 'localHost',
          'Accept-Encoding': 'gzip, deflate',
          'username':'sysadmin',
         'password':'122'}

#data = "<get_version/>"
r = requests.post(url, headers=header, data=data, timeout=100)

Read More
 2019-07-17
NLP-信息收集

背景 涉及内容 一些示例 原文摘自: https://github.com/fighting41love/funNLP背景最近需要从文本中抽取结构化信息,用到了很多github上的包,遂整理了一下,后续会不断更新。很多包非常有趣,值得收藏,满足大家的收集癖!涉及内容 中英文敏感词、语言检测、中外手机/...

Read More
 2019-07-10
windows dbg权限

1、 windows dbg权限 cuckoo 调用suricata接口1、 windows dbg权限管理员权限完全可以关闭系统中运行的任何用户模式下的进程,但是为何无法关闭呢,是因为Windows有一项机制叫“强制完整性控制”,IE保护模式处于低完整性,标准用户进程和管理员以标准用户权限运行时处于中完整...

Read More
 2014-10-09
Bitmap

bitmap所谓bitmap就是用一个bit位来标记某个元素对应的value,而key即是这个元素。由于采用bit为单位来存储数据,因此在可以大大的节省存储空间算法思想32位机器上,一个整形,比如 int a; 在内存中占32bit,可以用对应的32个bit位来表示十进制的0-31个数,bitmap算法利用这种思...

Read More
 2014-09-19
八种排序

1.直接插入排序 2.希尔排序(缩小增量排序) 3.简单选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 8.基数排序1.直接插入排序基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好...

Read More
 2014-06-26
Effective Java

一 创建和销毁对象 1.考虑用静态工厂方法代替构造器 2.遇到多个构造器参数时要考虑用构建器 3.用私有构造器或者枚举类型强化Singleton属性 4.通过私有构造器强化不可实例化的能力 5.避免创建不必要的对象 6.消除过期的对象引用 ...

Read More
 2014-06-10
SSH

登陆 过程 公钥登陆 远程操作 绑定本地端口 本地端口转发 远程端口转发 其他参数登陆-p指定主机的端口$ ssh -p port user@host默认端口为22$ ssh user@host默认使用本机用户名$ ssh host过程 远程主机接收到用户的登陆请求,把自己的公钥发给用...

Read More
 2014-04-15
Custom Fileupload

HTTP 分析 设计 关键代码 源码获取本文的目的是简要说明如何编写一个文件上传组件,使他的功能类似 commons-fileupload, 并在结尾处提供了完整代码的获取方式。HTTP本文讨论的是基于 HTTP 协议的文件上传,下面先来看看 HTTP 请求的真面目。首先,用 JavaSe 类库中的 ...

Read More
 2014-04-09
算法小汇

三色旗 汉诺塔 斐波那契数列 骑士周游 帕斯卡三角三色旗问题描述:一条绳子上悬挂了一组旗帜,旗帜分为三种颜色,现在需要把旗帜按顺序将相同的颜色的放在一起,没有旗帜的临时存放点,只能在绳子上操作,每次只能交换两个旗帜例如:原本旗帜的顺序为rwbrbwwrbwbrbwrbrw需要变成bbbbbbwwwww...

Read More
 2014-02-23
IP 类型

分类IP通过地址开头判断类型,将以 0,10,110 开头的地址分为ABC三类将ip转换成十进制后A类地址第一个字节在 0 - 127 之间,B类地址第一个字节在 128 - 191 之间C类地址第一个字节在 192 - 223 之间然后剩下的位被分为网络号与主机号,主机有两个特殊的值:主机号全部为0的ip代表一...

Read More
 2014-02-20
Linux启动流程

1.加载内核 2.启动初始化进程 3.确定运行级别 4.加载开机启动顺序 5.用户登陆 6.进入 login shell 7.打开 non-login shell1.加载内核操作系统接管硬件以后,首先读入/boot 目录下的内核文件。2.启动初始化进程内核文件加载以后,就开始运行第一个程序/sbi...

Read More
 2013-11-17
进制说明

抛开二进制不谈,我们先来看看10进制假设世界上没有负号且数字最大只有3位,我们要把 0~999 分成两部分,一部分表示负数,一部分表示正数,而且不影响他们的运算规律,应当如何去做?首先,最大的负数加上一等于零,那么用999表示最大的负数再合适不过,现在需要正负数各一半,那么正数部分应当为 0 ~ 499,负数部分...

Read More
 2013-11-17
进制说明

抛开二进制不谈,我们先来看看10进制假设世界上没有负号且数字最大只有3位,我们要把 0~999 分成两部分,一部分表示负数,一部分表示正数,而且不影响他们的运算规律,应当如何去做?首先,最大的负数加上一等于零,那么用999表示最大的负数再合适不过,现在需要正负数各一半,那么正数部分应当为 0 ~ 499,负数部分...

Read More
 2014-06-26
Effective Java

一 创建和销毁对象 1.考虑用静态工厂方法代替构造器 2.遇到多个构造器参数时要考虑用构建器 3.用私有构造器或者枚举类型强化Singleton属性 4.通过私有构造器强化不可实例化的能力 5.避免创建不必要的对象 6.消除过期的对象引用 ...

Read More
 2014-06-10
SSH

登陆 过程 公钥登陆 远程操作 绑定本地端口 本地端口转发 远程端口转发 其他参数登陆-p指定主机的端口$ ssh -p port user@host默认端口为22$ ssh user@host默认使用本机用户名$ ssh host过程 远程主机接收到用户的登陆请求,把自己的公钥发给用...

Read More
 2014-02-20
Linux启动流程

1.加载内核 2.启动初始化进程 3.确定运行级别 4.加载开机启动顺序 5.用户登陆 6.进入 login shell 7.打开 non-login shell1.加载内核操作系统接管硬件以后,首先读入/boot 目录下的内核文件。2.启动初始化进程内核文件加载以后,就开始运行第一个程序/sbi...

Read More
 2014-02-23
IP 类型

分类IP通过地址开头判断类型,将以 0,10,110 开头的地址分为ABC三类将ip转换成十进制后A类地址第一个字节在 0 - 127 之间,B类地址第一个字节在 128 - 191 之间C类地址第一个字节在 192 - 223 之间然后剩下的位被分为网络号与主机号,主机有两个特殊的值:主机号全部为0的ip代表一...

Read More
 2019-07-10
windows dbg权限

1、 windows dbg权限 cuckoo 调用suricata接口1、 windows dbg权限管理员权限完全可以关闭系统中运行的任何用户模式下的进程,但是为何无法关闭呢,是因为Windows有一项机制叫“强制完整性控制”,IE保护模式处于低完整性,标准用户进程和管理员以标准用户权限运行时处于中完整...

Read More
 2014-10-09
Bitmap

bitmap所谓bitmap就是用一个bit位来标记某个元素对应的value,而key即是这个元素。由于采用bit为单位来存储数据,因此在可以大大的节省存储空间算法思想32位机器上,一个整形,比如 int a; 在内存中占32bit,可以用对应的32个bit位来表示十进制的0-31个数,bitmap算法利用这种思...

Read More
 2014-09-19
八种排序

1.直接插入排序 2.希尔排序(缩小增量排序) 3.简单选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 8.基数排序1.直接插入排序基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好...

Read More
 2014-04-09
算法小汇

三色旗 汉诺塔 斐波那契数列 骑士周游 帕斯卡三角三色旗问题描述:一条绳子上悬挂了一组旗帜,旗帜分为三种颜色,现在需要把旗帜按顺序将相同的颜色的放在一起,没有旗帜的临时存放点,只能在绳子上操作,每次只能交换两个旗帜例如:原本旗帜的顺序为rwbrbwwrbwbrbwrbrw需要变成bbbbbbwwwww...

Read More
 2014-04-15
Custom Fileupload

HTTP 分析 设计 关键代码 源码获取本文的目的是简要说明如何编写一个文件上传组件,使他的功能类似 commons-fileupload, 并在结尾处提供了完整代码的获取方式。HTTP本文讨论的是基于 HTTP 协议的文件上传,下面先来看看 HTTP 请求的真面目。首先,用 JavaSe 类库中的 ...

Read More
 2019-07-17
NLP-信息收集

背景 涉及内容 一些示例 原文摘自: https://github.com/fighting41love/funNLP背景最近需要从文本中抽取结构化信息,用到了很多github上的包,遂整理了一下,后续会不断更新。很多包非常有趣,值得收藏,满足大家的收集癖!涉及内容 中英文敏感词、语言检测、中外手机/...

Read More
 2019-07-17
NLP-信息收集

背景 涉及内容 一些示例 原文摘自: https://github.com/fighting41love/funNLP背景最近需要从文本中抽取结构化信息,用到了很多github上的包,遂整理了一下,后续会不断更新。很多包非常有趣,值得收藏,满足大家的收集癖!涉及内容 中英文敏感词、语言检测、中外手机/...

Read More
 2020-04-02
Python3实现Http中间件

背景介绍

项目需要编写一个中间件,对面提供Http接口,首先肯定想到的就是对 基于python3的简易http-server进行改造。 但是项目实际过程中,中间件的调用可能来自多方,多个用户都会对这个接口进行异步的调用,所以该接口就需要对异步的调用进行及时的处理。

ps: 直接运行的话可以 python3 -m http.server

框架选择

首先可以想到的是http-server框架与flask框架。

  • 首先联想到cuckoo-agent模块,agent.py。 他是基于python2的SimpleHTTPServer实现的。对其并发性能没有深入研究,不过该agent主要部署在虚拟机中,同时也只会处理一个任务。
  • http-server比较简单,而flask则是python实现web服务器的通用框架。不管http-server、flask都是一个轻量级别的服务。
  • 对于并发请求http-server,它可以有多个连接,但是同时只能处理一条请求任务。该方式就一定会产生阻塞。一开始想的是利用 超时函数,超过固定的秒数就直接返回,但是该方式在多用户的情况下,不是一个很好的选择。
  • 对于flask 实现http服务,很显然更快捷,但是你会发现一些问题,就是你同一条指令、同一浏览器重复请求,会出现阻塞情况。尽管使用了多线程。 可以参考该连接:python flask如何解决同时请求同一个请求的阻塞问题?。当然也有解决方法,不过先入为主了。

因此,问题就变为了,如何处理http-server的并发问题: 后来也找到了解决方式 就是使用ThreadingMixIn,参考python3 HttpServer 实现多线程

代码demo

http-server 基于flask demo


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 参考: https://www.cnblogs.com/liangqihui/p/9139270.html
from flask import Flask, abort, request, jsonify

app = Flask(__name__)

# 测试数据暂时存放
tasks = []

@app.route('/add_task/', methods=['POST'])
def add_task():
    if not request.json or 'id' not in request.json or 'info' not in request.json:
        abort(400)
    task = {
        'id': request.json['id'],
        'info': request.json['info']
    }
    tasks.append(task)
    return jsonify({'result': 'success'})


@app.route('/get_task/', methods=['GET'])
def get_task():
    if not request.args or 'id' not in request.args:
        # 没有指定id则返回全部
        return jsonify(tasks)
    else:
        task_id = request.args['id']
        task = filter(lambda t: t['id'] == int(task_id), tasks)
        return jsonify(task) if task else jsonify({'result': 'not found'})


if __name__ == "__main__":
    # 将host设置为0.0.0.0,则外网用户也可以访问到这个服务
    app.run(host="0.0.0.0", port=8383, debug=True)

http-server 基于http.server demo

这边用到了一个装饰器,用于判断函数运行超时,返回信息。

from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import subprocess
import os
import time
from threading import Timer
import getpass
import logging
import os.path
import sys
import signal
import codecs
# from signal import signal, SIGPIPE, SIG_DFL


sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())

data = {'result': 'this is a agent!!'}
# 监听主机 & 端口
host = ('0.0.0.0', 4322)
# gvm指令请求超时时间,单位秒
gvm_order_timeout = 6


class Node():
    def __init__(self):
        self.connect_method = ""  # 连接方法
        self.host_name = "127.0.0.1"  # 主机名如:127.0.0.1


def timeout_exception():
    return (500, "run_gvm deal timeout")


def set_timeout(num, callback):
    def wrape(func):
        def handle(signum, frame):
            raise ("运行超时")

        def toDo(*args, **kwargs):
            try:
                signal.signal(signal.SIGALRM, handle)
                signal.alarm(num)  # 开启闹钟信号
                rs = func(*args, **kwargs)
                signal.alarm(0)  # 关闭闹钟信号
                return rs
            except:
                callback()

        return toDo

    return wrape


class Resquest(BaseHTTPRequestHandler):
    timeout = 10
    hostname = '127.0.0.1'
    port = 9390
    username = ''
    password = ''

    def handler(self, code, response):
        self.send_response(code)
        self.send_header('Content-type', 'application/txt')
        self.end_headers()
        self.wfile.write(response.encode())

    def timeout_callback(self, p):
        print('exe time out call back')
        print(p.id)
        try:
            p.kill()
        except Exception as error:
            print(error)

    def run_cmd(self, cmd):
        print('running:%s' % cmd)
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=os.getcwd(), shell=True)
        my_timer = Timer(self.timeout, self.timeout_callback, [p])
        my_timer.start()
        try:
            print("start to count timeout; timeout set to be %d \n" % (self.timeout,))
            out, stderr = p.communicate()
            # exit_code = p.returncode
        finally:
            my_timer.cancel()
            return out.decode()

    @set_timeout(gvm_order_timeout, timeout_exception)
    def run_app(self, node):
        return 200, "Parameters are missing"

    def do_GET(self):
        print(self.requestline)
        if self.path != '/hello':
            self.handler(404, "Parameters are missing")
            return
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps(data).encode())

    def do_POST(self):
        # print(self.headers)
        # print(self.command)
        # print(self.path, len(self.path), type(self.path))
        if self.headers['Referer'] != 'localHost':
            self.handler(404, "Parameters are missing")
            return
        if self.path == '/':
            self.path = '/tls'
        if self.path != '/tls' and self.path != '/ssh' and self.path != '/sock':
            self.handler(405, "Request method error")
            return
        # 读取请求体内容
        req_datas = self.rfile.read(int(self.headers['content-length']))
        # print(req_datas.decode())
        node = Node()
        node.gvm_cmd = req_datas.decode()
        node.host_name = self.headers['host_name']

        code, data = self.run_app(node)
        data_len = len(data)
        if data_len == 0 or data == "":
            self.handler(405, "response is null")
            return

        self.send_response(code)
        self.send_header('Content-type', 'application/xml')
        self.end_headers()
        # 返回信息量大 需分批写
        offset = 0
        n = data_len % 1024
        m = int(data_len / 1024)
        # print(data_len, m , n)
        for i in range(m):
            data_tmp = data[offset: offset + 1024]
            offset = offset + 1024
            self.wfile.write(data_tmp.encode())
        data_tmp = data[offset:]
        self.wfile.write(data_tmp.encode())


# 可以多线程,多队列的方式,
if __name__ == '__main__':
    server = HTTPServer(host, Resquest)
    server.timeout = 10
    print("Starting server, listen at: %s:%s" % host)
    # server.serve_forever()
    while True:
        server.handle_request()

http-server 基于ThreadingMixIn实现多线程处理:


from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import subprocess
import os
import time
from threading import Timer
import getpass
import logging
import os.path
import sys
import signal
import codecs
from socketserver import ThreadingMixIn
# from signal import signal, SIGPIPE, SIG_DFL


sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())

data = {'result': 'this is a agent!!'}
# 监听主机 & 端口
host = ('0.0.0.0', 4322)
# gvm指令请求超时时间,单位秒
gvm_order_timeout = 6


class Node():
    def __init__(self):
        self.connect_method = ""  # 连接方法
        self.host_name = "127.0.0.1"  # 主机名如:127.0.0.1


def timeout_exception():
    return (500, "run_gvm deal timeout")


def set_timeout(num, callback):
    def wrape(func):
        def handle(signum, frame):
            raise ("运行超时")

        def toDo(*args, **kwargs):
            try:
                signal.signal(signal.SIGALRM, handle)
                signal.alarm(num)  # 开启闹钟信号
                rs = func(*args, **kwargs)
                signal.alarm(0)  # 关闭闹钟信号
                return rs
            except:
                callback()

        return toDo

    return wrape


class Resquest(BaseHTTPRequestHandler):
    timeout = 10
    hostname = '127.0.0.1'
    port = 9390
    username = ''
    password = ''

    def handler(self, code, response):
        self.send_response(code)
        self.send_header('Content-type', 'application/txt')
        self.end_headers()
        self.wfile.write(response.encode())

    def timeout_callback(self, p):
        print('exe time out call back')
        print(p.id)
        try:
            p.kill()
        except Exception as error:
            print(error)

    def run_cmd(self, cmd):
        print('running:%s' % cmd)
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=os.getcwd(), shell=True)
        my_timer = Timer(self.timeout, self.timeout_callback, [p])
        my_timer.start()
        try:
            print("start to count timeout; timeout set to be %d \n" % (self.timeout,))
            out, stderr = p.communicate()
            # exit_code = p.returncode
        finally:
            my_timer.cancel()
            return out.decode()

    def run_app(self, node):
        print("demo1111")
        time.sleep(10)
        return 200, "Parameters are missing"

    def do_GET(self):
        print(self.requestline)
        if self.path != '/hello':
            self.handler(404, "Parameters are missing")
            return
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps(data).encode())

    def do_POST(self):
        # print(self.headers)
        # print(self.command)
        # print(self.path, len(self.path), type(self.path))
        if self.headers['Referer'] != 'localHost':
            self.handler(404, "Parameters are missing")
            return
        if self.path == '/':
            self.path = '/tls'
        if self.path != '/tls' and self.path != '/ssh' and self.path != '/sock':
            self.handler(405, "Request method error")
            return
        # 读取请求体内容
        req_datas = self.rfile.read(int(self.headers['content-length']))
        # print(req_datas.decode())
        node = Node()
        node.gvm_cmd = req_datas.decode()
        node.host_name = self.headers['host_name']

        code, data = self.run_app(node)
        data_len = len(data)
        if data_len == 0 or data == "":
            self.handler(405, "response is null")
            return

        self.send_response(code)
        self.send_header('Content-type', 'application/xml')
        self.end_headers()
        # 返回信息量大 需分批写
        offset = 0
        n = data_len % 1024
        m = int(data_len / 1024)
        # print(data_len, m , n)
        for i in range(m):
            data_tmp = data[offset: offset + 1024]
            offset = offset + 1024
            self.wfile.write(data_tmp.encode())
        data_tmp = data[offset:]
        self.wfile.write(data_tmp.encode())

class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
    pass

# 可以多线程,多队列的方式,
if __name__ == '__main__':
    #server = HTTPServer(host, Resquest)
    server = ThreadingHttpServer(host, Resquest)
    server.timeout = 10
    print("Starting server, listen at: %s:%s" % host)
    server.serve_forever()
    

client

	
import  requests

url = 'http://10.25.40.30:4321'
header = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
          'Accept': 'text / html,application / xml',
          'Referer': 'localHost',
          'Accept-Encoding': 'gzip, deflate',
          'username':'sysadmin',
         'password':'122'}

#data = "<get_version/>"
r = requests.post(url, headers=header, data=data, timeout=100)

Read More
 2020-04-03
docker学习记录


docker的网络模式

当你开始大规模使用Docker时,你会发现需要了解很多关于网络的知识。Docker作为目前最火的轻量级容器技术,有很多令人称道的功能,如Docker的镜像管理。然而,Docker同样有着很多不完善的地方,网络方面就是Docker比较薄弱的部分。因此,我们有必要深入了解Docker的网络知识,以满足更高的网络需求。本文首先介绍了Docker自身的4种网络工作方式,然后介绍一些自定义网络模式。

安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host

模式 简介 备注
host模式 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口 优势:性能高,适用于对网络效率有较高要求,但是对于端口会于宿主机冲突
bridge模式 此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信 拥有独立隔离的网络
none模式 该模式关闭了容器的网络功能,挂在这个网络下的容器除了 lo,没有其他任何网卡 在保密闭环的空间中使用,一般不使用
Container模式 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。 两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
自定义网络模式 Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建跨主机的网络 docker network create -d bridge –subnet 172.25.0.0/16 network_name

docker-host网络

11585881740_.pic_hd.jpg

docker-bridge网络

docker默认的网络连接方式为bridge,即桥接模式。在实际运行中会生成一个虚拟的网桥docker0,这边的虚拟网桥就类似于物理交换机的作用,而veth则可以类比物理交换机的端口 ,veth与容器内的eth0网卡 就是一队veth-pair,关于veth-pair技术可以参考该链接Linux-虚拟网络设备-veth pair,. 而docker0作为linux普通网桥,可以配置ip,这样便可以在三层进行网络通讯了。 20170828171704363.png

Docker 创建一个容器的时候,会执行如下操作:

  • 创建一对虚拟接口/网卡,也就是veth pair,分别放到本地主机和新容器中;
  • 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 vetha596da4;
  • 容器一端放到新容器中,并修改名字作为 eth0,这个网卡/接口只在容器的名字空间可见;
  • 从网桥可用地址段中(也就是与该bridge对应的network)获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 vetha596da4。
  • 完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。
  • 如果不指定–network,创建的容器默认都会挂到 docker0 上,使用本地主机上 docker0 接口的 IP 作为所有容器的默认网关。

iptables

ipforward

我们知道bridge模式下,会生成虚拟docker0,docker0为容器的默认网关。作为容器与外界通讯的媒介,docker0 与宿主机的网卡如何通讯呢? 这边其实就利用了linux多网卡数据包的转发功能。

Linux系统默认多网卡之间的数据包转发功能是关闭的。开启方法如下: 数据包转发功能默认配置 cat /proc/sys/net/ipv4/ip_forward 0 设置为1的时候转发 开机自动数据包转发 把下面代码添加到开机启动项/etc/rc.d/rc.local echo “1″ >/proc/sys/net/ipv4/ip_forward 或者修改/etc/sysctl.conf net.ipv4.ip_forward = 1

docker常见问题解答

Q:docker build的时候需要连接外网,但是有时候连接不上,为什么如何解决?

A: docker build 默认采用bridge模式,该方式需要桥接网卡,但是没看到。所以采用host 模式进行 docker build --network=host -t test . 参考:https://www.debugself.com/2018/01/17/docker_network/

附录

  1. docker容器的网络配置
  2. docker-compose配置ipv6

Read More
 2020-04-03
再谈cuckoo与suricata

再谈cuckoo与suricata suricata到底可以做哪些工作?再谈cuckoo与suricatasuricata 与cuckoo可以有机的进行结合。suricata还原的文件可以给cuckoo使用,cuckoo中恶意文件产生的数据流量报文,可以反过来给suricata回放规则检测。二者可以有机进行...

Read More