NAT穿透,UDP打洞程序

在看NAT穿透和UDP打洞原理,网上都是讲原理,没有程序,我把程序写出来。

server.py,辅助打洞的服务器。

peer.server.py,被打洞的节点。

peer.client.py,主动打洞的节点。

基本原理是:

1. peer.client向peer.server发个包,把自己的洞打好,这样peer.server可以给peer.client发包。

这个包会被NAT拒绝掉,所以peer.server是收不到这个包的(当然如果没有NAT,譬如在一台机器上,是可以收到的,就不算打洞了)。

2. peer.client向server发个包,server给peer.server发个包,peer.server再给peer.client发个包。

这样peer.client就可以给peer.server发包了。因为peer.client在第1步把自己的洞打好了,所以两者可以互发消息。

3. 打洞完毕,peer.client可以和peer.server通信。

用的三台虚拟机,server为bridge网卡,peer.server和peer.client为NAT网卡。

    #!/usr/bin/python2.6
    # server.py
    import signal;
    import sys;
    def handler(signum, frame):  
        print 'usr press ctrl+c, exit';  
        sys.exit(0)
    signal.signal(signal.SIGINT, handler)
     
    ##################################################################
    import socket;
    import json;
    import time;
     
    if len(sys.argv) <= 1:
        print """Usage: %s <port>
            port                the [UDP] port to bind.
    For example:
            %s 2013"""%(sys.argv[0], sys.argv[0]);
        sys.exit(1);
    port=sys.argv[1];
     
    print "NAT traversal & udp hold-punching"
    print "Server-side which used to help the client behind NAT to hold-punching."
     
    max_packet_size = 4096
     
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
    s.bind(('', int(port)));
    print "UDP bind at %s"%(port);
     
    peers = [];
    def get_peer(code, required_peer_id):
        for peer in peers:
            id = peer["id"];
            if id != required_peer_id:
                continue;
            (peer_id, peer_address) = (id, peer["address"]);
            return (code, peer_id, peer_address);
        return (1, 0, None);
     
    while True:
        (data, address) = s.recvfrom(max_packet_size);
        #print "get data from %s: %s"%(address, data);
        
        obj = json.loads(data);
        action = obj["action"];
        code = 0;
        
        if action == "join":
            id = obj["id"];
            
            for i in range(0, len(peers)):
                if peers[i]["id"] != id:
                    continue;
                del peers[i];
                break;
                    
            peers.append({"id":id, "address":address});
            print "[join] %s %s"%(id, address);
            continue;
            
        if action == "find":
            (code, peer_server_id, peer_server_address) = get_peer(code, obj["peer_server_id"]);
            (code, peer_client_id, peer_client_address) = get_peer(code, obj["peer_client_id"]);
            print "[find] %s %s find %s %s"%(peer_client_id, peer_server_id, peer_server_id, peer_server_address);
            s.sendto(json.dumps({"code": code, "peer_server_address": peer_server_address, "peer_server_id": peer_server_id, "peer_client_address":peer_client_address}), address);
            
        if action == "hole_punching":
            (code, peer_server_id, peer_server_address) = get_peer(code, obj["peer_server_id"]);
            (code, peer_client_id, peer_client_address) = get_peer(code, obj["peer_client_id"]);
            
            time.sleep(3);
            print "[hole-punching] (%s)%s <==> (%s)%s"%(peer_client_id, peer_client_address, peer_server_id, peer_server_address);
            s.sendto(json.dumps({"action": "hole_punching", "peer_server_address":peer_server_address, "peer_client_address": peer_client_address}), tuple(peer_server_address));
        pass;
     
    s.close();


    #!/usr/bin/python2.6
    # peer.server.py
    import signal;
    import sys;
    def handler(signum, frame):  
        print 'usr press ctrl+c, exit';  
        sys.exit(0)
    signal.signal(signal.SIGINT, handler)
     
    ##################################################################
    import socket;
    import json;
    import time;
     
    if len(sys.argv) <= 3:
        print """Usage: %s <server> <port> <id>
            server              the server to connect to.
            port                the UDP port to connect to.
            id                  the id of peer.
    For example:
            %s 192.168.20.118 2013 peer.server"""%(sys.argv[0], sys.argv[0]);
        sys.exit(1);
    (server, port, id) = sys.argv[1:];
    port = int(port);
     
    print "NAT traversal & udp hold-punching"
    print "Peer-server-side which is behind NAT to hold-punching."
    print "peer-server means it wait for peer-client to hole-punching with"
     
    server_endpoint = (server, port)
    max_packet_size = 4096
     
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
     
    # join server
    s.sendto(json.dumps({"action": "join", "id": id}), server_endpoint);
    print "[join] %s"%(id)
     
    while True:
        # recv request from server.
        (data, address) = s.recvfrom(max_packet_size);
        #print "get data from %s: %s"%(address, data);
        obj = json.loads(data);
            
        action = obj["action"];
        if action != "hole_punching":
            continue;
            
        if "peer_client_address" not in obj:
            continue;
            
        peer_client_address = obj["peer_client_address"];
        peer_server_address = obj["peer_server_address"]
        print "[open_hole] by %s"%(str(address));
        
        # send a packet to peer.client to open the hole.
        s.sendto(json.dumps({"action": "open_hole", "id": id}), tuple(peer_client_address));
        
        data = json.dumps({"action": "video", "video": "xxxxx video xxxxxx"})
        while True:
            ret = s.sendto(data, tuple(peer_client_address));
            print "[success] %s ===> %s: %s"%(peer_server_address, peer_client_address, data);
            time.sleep(3);
        
        break;
     
    s.close();


    #!/usr/bin/python2.6
    # peer.client.py
    import signal;
    import sys;
    def handler(signum, frame):  
        print 'usr press ctrl+c, exit';  
        sys.exit(0)
    signal.signal(signal.SIGINT, handler)
     
    ##################################################################
    import socket;
    import json;
    import time;
     
    if len(sys.argv) <= 4:
        print """Usage: %s <server> <port> <id> <peer_server_id>
            server              the server to connect to.
            port                the UDP port to connect to.
            id                  the id of peer.
            peer_server_id     the id of peer to hole-punching to.
    For example:
            %s 192.168.20.118 2013 peer.client peer.server"""%(sys.argv[0], sys.argv[0]);
        sys.exit(1);
    (server, port, id, peer_server_id)=sys.argv[1:];
    port = int(port);
     
    print "NAT traversal & udp hold-punching"
    print "Peer-side which is behind NAT to hold-punching."
     
    server_endpoint = (server, port)
    max_packet_size = 4096
     
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
     
    # join server
    s.sendto(json.dumps({"action": "join", "id": id}), server_endpoint);
    print "[join] %s"%(id)
     
    (peer_client_address, peer_server_address) = (None, None);
    while True:
        # find the peer to hole-punching
        s.sendto(json.dumps({"action": "find", "peer_client_id": id, "peer_server_id": peer_server_id}), server_endpoint);
     
        # discovery result
        (data, address) = s.recvfrom(max_packet_size);
        #print "get data from %s: %s"%(address, data);
        obj = json.loads(data);
            
        code = obj["code"];
        if code is not 0:
            print "[find] peer %s not found"%(peer_server_id);
            time.sleep(1);
            continue;
        peer_server_address = obj["peer_server_address"];
        peer_client_address = obj["peer_client_address"];
        break;
     
    # to punching hole.
    print "[find] peer(%s) address is %s"%(peer_server_id, peer_server_address);
    # step 1: directly send a packet to peer, open self tunnel.
    print "[hole-punching] try to punching hole to %s"%(peer_server_address);
    s.sendto(json.dumps({"action": "hole_punching", "peer_client_id": id, "peer_client_address":peer_client_address, "peer_server_address":peer_server_address}), tuple(peer_server_address));
    # step 2: send a packet to server, open the peer tunnel.
    print "[hole-punching] try to use server %s to punching hole"%(str(server_endpoint));
    s.sendto(json.dumps({"action": "hole_punching", "peer_client_id": id, "peer_server_id": peer_server_id}), server_endpoint);
     
    while True:
        (data, address) = s.recvfrom(max_packet_size);
        print "[success] %s ===> %s: %s"%(address, peer_client_address, data);
     
    s.close();


执行结果如下:

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值