В современных сетях многие устройства находятся за NAT (трансляцией сетевых адресов) или межсетевыми экранами, что затрудняет прямой доступ к этим устройствам. В этом случае технология проникновения в сеть становится очень важной. В этой статье будут представлены три широко используемые технологии проникновения в сеть: пробивание отверстий TCP, пробивание отверстий UDP и UPnP.
TCP Hole Punching — это метод, который позволяет двум клиентам за NAT установить прямое соединение через сторонний сервер. NAT обычно не позволяет внешним хостам напрямую взаимодействовать с внутренними хостами, поэтому для установления соединения требуется внешний сервер.
Ниже приведен простой пример Python, демонстрирующий процесс подключения через пробивание отверстий TCP.
import socket
# Server listens for incoming connections and exchanges client information
def server():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 12345))
s.listen(2)
print("Server waiting for connections...")
conn_a, addr_a = s.accept()
print(f"Client A connected: {addr_a}")
conn_b, addr_b = s.accept()
print(f"Client B connected: {addr_b}")
# Exchange addresses
conn_a.send(f"{addr_b[0]}:{addr_b[1]}".encode())
conn_b.send(f"{addr_a[0]}:{addr_a[1]}".encode())
conn_a.close()
conn_b.close()
s.close()
# Clients attempt to connect to each other using exchanged information
def client():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('server_ip', 12345)) # Replace 'server_ip' with the actual IP of the server
peer_info = s.recv(1024).decode()
peer_ip, peer_port = peer_info.split(':')
# Attempt to connect to peer
try:
peer_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
peer_socket.connect((peer_ip, int(peer_port)))
print("Connected to peer!")
except Exception as e:
print(f"Failed to connect to peer: {e}")
s.close()
Перфорация UDP аналогична перфорации TCP. Это технология, которая позволяет двум хостам за NAT устанавливать прямое соединение UDP через сторонний сервер. В отличие от TCP, UDP — это протокол без установления соединения, позволяющий узлу NAT более легко принимать запросы на подключение извне.
import socket
# UDP Server to exchange addresses
def udp_server():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('0.0.0.0', 12345))
print("Server waiting for messages...")
data_a, addr_a = s.recvfrom(1024)
print(f"Received from A: {addr_a}")
data_b, addr_b = s.recvfrom(1024)
print(f"Received from B: {addr_b}")
# Exchange addresses
s.sendto(f"{addr_b[0]}:{addr_b[1]}".encode(), addr_a)
s.sendto(f"{addr_a[0]}:{addr_a[1]}".encode(), addr_b)
# UDP Client to communicate through hole punching
def udp_client():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(b'Hello from client', ('server_ip', 12345)) # Replace 'server_ip' with actual server IP
peer_info, _ = s.recvfrom(1024)
peer_ip, peer_port = peer_info.decode().split(':')
# Send message to peer
s.sendto(b'Hello peer!', (peer_ip, int(peer_port)))
try:
response, _ = s.recvfrom(1024)
print(f"Received from peer: {response}")
except socket.timeout:
print("No response from peer")
s.close()
UPnP (Universal Plug and Play) — это сетевой протокол, который позволяет устройствам автоматически обнаруживать другие устройства в сети и взаимодействовать с ними. В среде NAT UPnP может автоматически открывать порты маршрутизатора, позволяя внешним устройствам получать доступ к устройствам, расположенным во внутренней сети.
UPnP в основном используется в домашних сетях и небольших локальных сетях. Он упрощает процесс связи устройств в сети за счет автоматической настройки устройств.
Можно использовать сторонние библиотеки. miniupnpc
осознать UPnP Сопоставление портов, следующее Python Пример.
pip install miniupnpc
import miniupnpc
def upnp_port_mapping():
upnp = miniupnpc.UPnP()
upnp.discoverdelay = 200
upnp.discover() # Discover UPnP devices
upnp.selectigd() # Select Internet Gateway Device
external_port = 12345
internal_port = 54321
local_ip = upnp.lanaddr # Get local IP address
# Add port mapping (TCP)
upnp.addportmapping(external_port, 'TCP', local_ip, internal_port, 'Test Port Mapping', '')
print(f"Port {external_port} mapped to {local_ip}:{internal_port} (TCP)")
# Optionally, remove the port mapping
# upnp.deleteportmapping(external_port, 'TCP')
upnp_port_mapping()
Эти три технологии очень важны в приложениях P2P, особенно в средах NAT или межсетевых экранах, поскольку они могут значительно повысить вероятность успешных соединений.