The cornerstone of p2p: Happy udp hole drilling experiment

Because of the epidemic at home office, remote operation of the company's computer. All of a sudden, I want to try what I always wanted to do a long time ago: udp hole drilling. After all, men change, like to drill.

The test procedure is recorded as follows:

Note: the computer at home is recorded as PC UU a, and the computer of the company is recorded as PC UU B

1. Use stun service to detect the NAT types of computers on both sides and get the internal and external network addresses on both sides.

Use here https://github.com/ccding/go-stun This library. Because go stun does not output the port of native udp on the console, you need to add a sentence to its source code:

fmt.Println("local addr:", conn.LocalAddr().String())
func (c *Client) Discover() (NATType, *Host, error) {
	if c.serverAddr == "" {
		c.SetServerAddr(DefaultServerAddr)
	}
	serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr)
	if err != nil {
		return NATError, nil, err
	}
	// Use the connection passed to the client if it is not nil, otherwise
	// create a connection and close it at the end.
	conn := c.conn
	if conn == nil {
		conn, err = net.ListenUDP("udp", nil)
        // Add a new port here to print out the local port
		fmt.Println("local addr:", conn.LocalAddr().String())
		if err != nil {
			return NATError, nil, err
		}
		defer conn.Close()
	}
	return c.discover(conn, serverUDPAddr)
}

After repacking and generating go-stun.exe, execute the following commands in PC a and PC B respectively

 go-stun.exe -s stun.sipgate.net:10000

stun.sipgate.net:10000 is a free public network stun server. You must select one that can be used. Because of some indescribable reasons, most stun servers cannot be accessed

PC a output is as follows:

PC B output is as follows:

Fortunately, both PC a and PC B belong to port limited NAT, which can be achieved in theory.

2. Write python code

After the previous step, we have:

PC a internal port 52280 external address xxx.xxx.0.195

PC? B internal port 64320 external address xxx.xxx.169.96

Then, the general work of py program is as follows:

1. Create a udp socket and bind it to the internal port of the machine

2. Start a sending thread, and send messages to the external address of the other party every several times

3. The main process starts a cycle to receive messages from the other side

The py scripts of PC a and PC B should be exactly the same. The difference is only some parameters.

The py script of PC A is as follows:

import socket
import time
from threading import Thread

local_port = 52280
remote_ip, remote_port = "xxx.xxx.169.96", 64320
msg = "hello, i am aaaaaaaaaaaa"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", local_port))


class SendThread(Thread):

    def run(self):
        while True:
            s.sendto(msg.encode(), (remote_ip, remote_port))
            print("sent")
            time.sleep(1)


st = SendThread()
st.start()

while True:
    data = s.recv(1024)  # 1024 bytes received at a time
    print(data.decode())  # decode() decodes bytes received

Similarly, the py script of PC ﹣ B is as follows:

import socket
import time
from threading import Thread

local_port = 64320
remote_ip, remote_port = "xxx.xxx.0.195", 52280
msg = "hello, i am bbbbbbbb"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", local_port))


class SendThread(Thread):

    def run(self):
        while True:
            s.sendto(msg.encode(), (remote_ip, remote_port))
            print("sent")
            time.sleep(1)


st = SendThread()
st.start()

while True:
    data = s.recv(1024)  # 1024 bytes received at a time
    print(data.decode())  # decode() decodes bytes received

3. Start drilling!

Run py script on PC a and PC B respectively

Console output of PC A:

sent
sent
sent
sent
sent
hello, i am bbbbbbbb
sent
hello, i am bbbbbbbb
sent
hello, i am bbbbbbbb
sent
hello, i am bbbbbbbb
sent
hello, i am bbbbbbbb
sent

Console output of PC B:

sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa
sent
hello, i am aaaaaaaaaaaa

Obviously, it's a perfect hole

4. postscript

A simple hello message represents the infinite possibility of file transfer and remote desktop

38 original articles published, 25 praised, 50000 visitors+
Private letter follow

Tags: socket network github Python

Posted on Thu, 12 Mar 2020 05:34:45 -0400 by lawnmowerman