zoukankan      html  css  js  c++  java
  • 用Linux的iptables和Python模拟广域网

    引用:http://www.cnblogs.com/yushih/archive/2010/06/01/1749378.html

    问题:有人在豆瓣Python版提出“在一台PC上模拟多个IP地址向服务器发起socket连接,并在建立连接后发数据包“的需求。具体要求是“可以在 界面上输入想要模拟的IP地址的范围,比如我想模拟100个用户,就输入192.168.4.100——192.168.4.200,然后自动以这些IP 地址向服务器发socket连接和一些数据“,“服务器侧是一个注册系统,以IP和序列号区分不同用户,我要想进行压力测试必须模拟不同的IP地址“。环 境是“测试所有使用的都是私网地址,而且环境比较独立,所以不必考虑NAT和IP冲突问题“。限制:”服务器侧要是能动就好了,就是不能改动“。以下是我 的解决方法。

    搭建环境:服务器端环境不限。客户端必须是Linux。服务器和客户直接通过LAN连接。以上只是逻辑要求,可以用虚拟机在一台电脑上实现。客户端ip地 址设置为cip,掩码nm,服务器端ip地址设置为sip(sip&nm == cip&nm),掩码nm,缺省网关cip(注意,是把服务器的缺省网关地址设置为客户ip地址。课后练习:为什么?)。

    软件安装:在客户端装nfqueue-bindings(http://software.inl.fr/trac/wiki/nfqueue- bindings)。有大量的依赖需要安装,不过不需要Perl,只要把CMakeLists.txt中“ADD_SUBDIRECTORY(perl) “这一行去掉。另外libnetfilter-queue要自己下载编译安装,至少在我的机器上用rpm安装后nfqueue-bindings不认。

    运行ip模拟器:在客户端以root权限运行wansim.py(代码在后面),命令行参数为:
    python wansim.py sip cip ip_range
    其中sip为上面设置的服务器ip,cip为上面设置的客户端机器ip,ip_range为要模拟的ip范围,例如:
    1.1.1.1-254

    1.1.1-254.1-254

    222-235.1-8.2.3-6 

    限制:模拟ip不能进入客户端-服务器所用LAN的子网ip范围,即对任何模拟ip地址fip:fip&nm != sip&nm(课后作业:为什么?)。
    ip模拟器开始运行后,所有从客户端发起到服务器端的tcp会话将被ip模拟器从指定ip范围中随机分配一个ip。服务器程序看到的是这个模拟的ip,而不是cip。

    运行:运行服务器。在客户机上运行客户端测试软件。以下是我Windows上服务器看到的效果:

     

    很明显服务器看到的是模拟出来的客户ip。

     最后,上代码,再次声明,本人不负任何责任。以下代码进入公共域。

    wansim.py
    import sys
    sys.path.append(r'/usr/local/lib/python2.6/site-packages')
    import nfqueue
    import time
    from socket import AF_INET, AF_INET6, inet_ntoa, inet_aton
    from dpkt import ip, tcp, hexdump
    import re
    import sys
    import random




    svr_ip=sys.argv[1]

    my_ip=sys.argv[2]


    def parse():
            
    for r in sys.argv[3].split('.'):
                    
    if '-' in r: #xxx-yyy
                            m=re.match(r'(\d+)-(\d+)', r)
                            
    yield range(int(m.group(1)), int(m.group(2))+1)
                    
    else#xxx
                            yield range(int(r), int(r)+1)
    fake_ip_range=list(parse())
    def get_fake_ip():
            ip = '.'.join(str(random.choice(r)) for r in fake_ip_range)
            
    print 'fake ip: ', ip
            
    return ip
            
    #Track connection by src port. This is very crude. Should watch tcp more closely.
    port2ip={}

    time0 = None

    def cb(i,payload):
            
    global time0
            data = payload.get_data()
            pkt = ip.IP(data)
            
    if not time0:
                    time0=time.time()
            
    print time.time()-time0,\
                  
    "source: %s" % inet_ntoa(pkt.src),\
                  
    "dest: %s" % inet_ntoa(pkt.dst)
            
    if pkt.p == ip.IP_PROTO_TCP:
                    
    #outgoing to target server
                    if inet_ntoa(pkt.dst) == svr_ip:
                            
    if pkt.tcp.sport in port2ip:
                                    pkt.src = port2ip[pkt.tcp.sport]
                            
    else:
                                    fip = inet_aton(get_fake_ip())
                                    port2ip[pkt.tcp.sport]=fip
                                    pkt.src = fip

                    
    #incoming from target server
                    elif inet_ntoa(pkt.src) == svr_ip and \
                         inet_ntoa(pkt.dst) != my_ip:
                            
    #a stronger condition is to check if it is one of our fake ip
                            pkt.dst = inet_aton(my_ip)
                            
                    pkt.tcp.sum = 0
                    pkt.sum = 0
                    payload.set_verdict_modified(
                            nfqueue.NF_ACCEPT,str(pkt),len(pkt))

                    
    return 0
            payload.set_verdict(nfqueue.NF_ACCEPT)

            sys.stdout.flush()
            
    return 1

    def run(cmd):
            
    from commands import getstatusoutput
            (s, o) = getstatusoutput(cmd)
            
    print cmd
            
    print 'exit code ', s
            
    if len(o):
                    
    print o

    cmds = [
            
    #intercept outgoing packets
            "iptables -t mangle -A POSTROUTING -p tcp -d %s -j NFQUEUE" % svr_ip,
            
    #intercept incoming packets
            "iptables -t mangle -A PREROUTING  -p tcp -s %s -j NFQUEUE" % svr_ip,
            
    #"iptables -A INPUT -p tcp -i eth1 -j NFQUEUE "
    ]

    for c in cmds:
            run(c)

    = nfqueue.queue()

    print "open"
    q.open()

    print "bind"
    q.bind(AF_INET);

    print "setting callback"
    q.set_callback(cb)

    print "creating queue"
    q.create_queue(0)

    print "trying to run"
    try:
            q.try_run()
    except KeyboardInterrupt, e:
            
    print "interrupted"


    print "unbind"
    q.unbind(AF_INET)

    print "close"
    q.close()

    for c in cmds:
            run(c.replace('-A''-D'))

    如果需要更改模拟ip分配的方式,只需修改get_fake_ip这个函数。 

  • 相关阅读:
    太原市圆通快递网点
    快递单号查询小工具
    C#快递单号查询源码
    爱快递快递接口使用说明
    如何把网站及数据库部署到Windows Azure
    从window.console&&console.log(123)浅谈JS的且运算逻辑(&&)
    C# Enum 简易权限设计 使用FlagsAttribute属性
    Lambda 表达式(C# 编程指南)
    C# list使用方法
    SharePoint Server 2013介绍v2
  • 原文地址:https://www.cnblogs.com/sode/p/2236226.html
Copyright © 2011-2022 走看看