赞
踩
假设云主机eth0: 47.93.27.106
tun0: inet 10.8.0.1 netmask 255.255.255.0
Show rules for a specific zone (public)
sudo firewall-cmd --zone=public --list-all
Add the tun0
interface to the public
zone:
sudo firewall-cmd --zone=public --add-interface=tun0 --permanent
Check the active zones again to confirm that tun0
has been added:
sudo firewall-cmd --get-active-zones
Add the forward port rules
sudo firewall-cmd --zone=public --add-forward-port=port=14662:proto=tcp:toport=4662:toaddr=10.8.0.2 --permanent
(10.8.0.1)开放端口14662 接收外部流量, 转发到10.8.0.2:4662
修改内核参数支持IPv4防火墙端口转发
- sudo sysctl -w net.ipv4.ip_forward=1
- sudo sh -c 'echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf'
配置NAT确保public zone的流量转到en0:
- sudo iptables -t nat -A PREROUTING -p tcp --dport 14662 -j DNAT --to-destination 10.8.0.2:4662
- sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
确保iptables-serverices软件包安装了
sudo yum install iptables-services
保存、重启iptables,让配置生效
- sudo service iptables save
- sudo systemctl restart iptables
- sudo systemctl enable iptables
重启防火墙firewalld
- sudo firewall-cmd --reload
- sudo systemctl restart firewalld
查看改动的配置
- sudo firewall-cmd --list-all --zone=public
- sudo iptables -L -t nat
在这台VPS上 telnet 10.8.0.2 4662
windows客户端先连接上Open***, 另一台vps
当然也可以用在线工具open-ports, TCP可以支持, UDP还是要自己写个简单的代码测试。
windows客户端
同理udp 4672
- sudo firewall-cmd --zone=public --add-forward-port=port=14672:proto=udp:toport=4672:toaddr=10.8.0.2
- sudo firewall-cmd --zone=public --add-forward-port=port=14672:proto=udp:toport=4672:toaddr=10.8.0.2 --permanent
- sudo firewall-cmd --reload
- sudo iptables -t nat -A PREROUTING -p udp --dport 14672 -j DNAT --to-destination 10.8.0.2:4672
- sudo service iptables save
sudo systemctl restart firewalld
发送UDP报文
echo -n "Test UDP Packet" | nc -u 47.93.27.106 14672 # 以下C代码同理
udp_sender.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <unistd.h>
-
- int main(int argc, char *argv[]) {
- if (argc != 4) {
- fprintf(stderr, "Usage: %s <server_ip> <server_port> <message>\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- const char *server_ip = argv[1];
- int server_port = atoi(argv[2]);
- const char *message = argv[3];
-
- int sockfd;
- struct sockaddr_in server_addr;
-
- // Create socket
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("Socket creation failed");
- exit(EXIT_FAILURE);
- }
-
- memset(&server_addr, 0, sizeof(server_addr));
-
- // Fill server information
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(server_port);
- server_addr.sin_addr.s_addr = inet_addr(server_ip);
-
- // Send UDP packet
- if (sendto(sockfd, message, strlen(message), 0, (const struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
- perror("Send failed");
- close(sockfd);
- exit(EXIT_FAILURE);
- }
-
- printf("UDP packet sent.\n");
-
- // Receive echoed packet
- char recvBuffer[512];
- struct sockaddr_in fromAddr;
- socklen_t fromAddrLen = sizeof(fromAddr);
- int bytesReceived = recvfrom(sockfd, recvBuffer, 512, 0, (struct sockaddr*)&fromAddr, &fromAddrLen);
- if (bytesReceived < 0) {
- perror("Receive failed");
- close(sockfd);
- exit(EXIT_FAILURE);
- }
-
- // Null-terminate the received data
- recvBuffer[bytesReceived] = '\0';
-
- // Print received message
- printf("Received echoed UDP packet: %s\n", recvBuffer);
-
- // Close socket
- close(sockfd);
- return 0;
- }
可以把本地eMule先停掉,防止UDP 4672端口被占用
UDPEchoServer.java
- package org.example;
-
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
-
- public class UDPEchoServer extends JFrame {
- private JTextField portField;
- private JButton startButton;
- private JTextArea messageArea;
- private DatagramSocket socket;
- private boolean running;
-
- public UDPEchoServer() {
- setTitle("UDP Echo Server");
- setSize(400, 300);
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- setLocationRelativeTo(null);
-
- JPanel panel = new JPanel(new BorderLayout());
- portField = new JTextField();
- startButton = new JButton("Start Server");
- messageArea = new JTextArea();
- messageArea.setEditable(false);
-
- JPanel topPanel = new JPanel(new BorderLayout());
- topPanel.add(new JLabel("Port:"), BorderLayout.WEST);
- topPanel.add(portField, BorderLayout.CENTER);
- topPanel.add(startButton, BorderLayout.EAST);
-
- panel.add(topPanel, BorderLayout.NORTH);
- panel.add(new JScrollPane(messageArea), BorderLayout.CENTER);
-
- add(panel);
-
- startButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- if (!running) {
- int port;
- try {
- port = Integer.parseInt(portField.getText());
- } catch (NumberFormatException ex) {
- JOptionPane.showMessageDialog(UDPEchoServer.this, "Invalid port number", "Error", JOptionPane.ERROR_MESSAGE);
- return;
- }
- startServer(port);
- } else {
- stopServer();
- }
- }
- });
- }
-
- private void startServer(int port) {
- try {
- socket = new DatagramSocket(port);
- running = true;
- startButton.setText("Stop Server");
- portField.setEditable(false);
- messageArea.append("Server started on port " + port + "\n");
-
- Thread serverThread = new Thread(new Runnable() {
- @Override
- public void run() {
- byte[] buffer = new byte[1024];
- while (running) {
- try {
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
- socket.receive(packet);
- String received = new String(packet.getData(), 0, packet.getLength());
- InetAddress address = packet.getAddress();
- int clientPort = packet.getPort();
- messageArea.append("Received: " + received + " from " + address + ":" + clientPort + "\n");
-
- // Echo the message back
- DatagramPacket response = new DatagramPacket(packet.getData(), packet.getLength(), address, clientPort);
- socket.send(response);
- messageArea.append("Echoed: " + received + " to " + address + ":" + clientPort + "\n");
- } catch (Exception ex) {
- if (running) {
- messageArea.append("Error: " + ex.getMessage() + "\n");
- }
- }
- }
- }
- });
- serverThread.start();
- } catch (Exception ex) {
- messageArea.append("Error starting server: " + ex.getMessage() + "\n");
- }
- }
-
- private void stopServer() {
- running = false;
- socket.close();
- startButton.setText("Start Server");
- portField.setEditable(true);
- messageArea.append("Server stopped\n");
- }
-
- public static void main(String[] args) {
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- new UDPEchoServer().setVisible(true);
- }
- });
- }
- }
本地启动Java UDP Echo server测试UDP port number 4672连通性
云主机VPS发到本地Windows:
确认从云主机14672端口的UDP流量转发到windows本机的UDP 4672服务,检查UDP Echo server
确认接收到的内容与远程主机发过来的一样。
当然如果本机eMule已经启动了,端口已被占用,则需要用wireshark看
打开wireshark找到tunnel adaptor 用wireshark过滤条件
udp and ip.addr == 10.8.0.2 and udp.port == 4672
如果是从windows端
- #include <WinSock2.h>
- #include <WS2tcpip.h>
- #include <stdio.h>
-
- #pragma comment(lib, "Ws2_32.lib")
-
- int main(int argc, char* argv[]) {
- // Validate command-line arguments
- if (argc != 4) {
- printf("Usage: %s <server_ip> <server_port> <message>\n", argv[0]);
- return 1;
- }
-
- const char* server_ip = argv[1];
- int server_port = atoi(argv[2]);
- const char* message = argv[3];
-
- // Initialize Winsock
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
- printf("WSAStartup failed. Error Code : %d", WSAGetLastError());
- return 1;
- }
-
- // Create socket
- SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sockfd == INVALID_SOCKET) {
- printf("Socket creation failed. Error Code : %d", WSAGetLastError());
- WSACleanup();
- return 1;
- }
-
- // Server address structure
- sockaddr_in serverAddr;
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_port = htons(server_port);
- inet_pton(AF_INET, server_ip, &serverAddr.sin_addr);
-
- // Send UDP packet
- int bytesSent = sendto(sockfd, message, strlen(message), 0, (sockaddr*)&serverAddr, sizeof(serverAddr));
- if (bytesSent == SOCKET_ERROR) {
- printf("Send failed. Error Code : %d", WSAGetLastError());
- closesocket(sockfd);
- WSACleanup();
- return 1;
- }
-
- printf("UDP packet sent.\n");
-
- // Receive echoed packet
- char recvBuffer[512];
- sockaddr_in fromAddr;
- int fromAddrLen = sizeof(fromAddr);
- int bytesReceived = recvfrom(sockfd, recvBuffer, 512, 0, (sockaddr*)&fromAddr, &fromAddrLen);
- if (bytesReceived == SOCKET_ERROR) {
- printf("Receive failed. Error Code : %d", WSAGetLastError());
- closesocket(sockfd);
- WSACleanup();
- return 1;
- }
-
- // Null-terminate the received data
- recvBuffer[bytesReceived] = '\0';
-
- // Print received message
- printf("Received echoed UDP packet: %s\n", recvBuffer);
-
- // Close socket
- closesocket(sockfd);
- WSACleanup();
- return 0;
- }
udp_sender.exe 47.93.27.106 14672 "Test UDP Packet"
服务端: sudo tcpdump -i any udp port 14672 -XX
这样,借助Open***, iptables & firewalld 在没有公网IP的条件下把本机TCP 4662 映射到远程云主机 TCP 14662, 把本机UDP 4672映射到远程云主机UDP 14672。花生壳 就赚不到我们的钱了。
windows UDP Echo server:
- #include <iostream>
- #include <winsock2.h>
- #include <ws2tcpip.h>
- #include <windows.h>
-
- #pragma comment(lib, "Ws2_32.lib")
-
- #define BUFFER_SIZE 1024
-
- int main() {
- WSADATA wsaData;
- SOCKET serverSocket = INVALID_SOCKET;
- sockaddr_in serverAddr, clientAddr;
- int clientAddrSize = sizeof(clientAddr);
- char buffer[BUFFER_SIZE];
-
- // Initialize Winsock
- if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
- std::wcerr << L"WSAStartup failed with error: " << WSAGetLastError() << std::endl;
- return 1;
- }
-
- // Create a socket for the server
- serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (serverSocket == INVALID_SOCKET) {
- std::wcerr << L"Socket creation failed with error: " << WSAGetLastError() << std::endl;
- WSACleanup();
- return 1;
- }
-
- int port;
- std::wcout << L"Enter port number: ";
- std::wcin >> port;
-
- // Setup the UDP server address structure
- memset(&serverAddr, 0, sizeof(serverAddr));
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_addr.s_addr = INADDR_ANY;
- serverAddr.sin_port = htons(port);
-
- // Bind the socket to the port
- if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
- std::wcerr << L"Bind failed with error: " << WSAGetLastError() << std::endl;
- closesocket(serverSocket);
- WSACleanup();
- return 1;
- }
-
- std::wcout << L"UDP Echo Server started on port " << port << std::endl;
-
- while (true) {
- // Receive a message from a client
- int bytesReceived = recvfrom(serverSocket, buffer, BUFFER_SIZE - 1, 0, (sockaddr*)&clientAddr, &clientAddrSize);
- if (bytesReceived == SOCKET_ERROR) {
- std::wcerr << L"recvfrom failed with error: " << WSAGetLastError() << std::endl;
- break;
- }
-
- // Null-terminate the received data
- buffer[bytesReceived] = '\0';
-
- // Echo the message back to the client
- int bytesSent = sendto(serverSocket, buffer, bytesReceived, 0, (sockaddr*)&clientAddr, clientAddrSize);
- if (bytesSent == SOCKET_ERROR) {
- std::wcerr << L"sendto failed with error: " << WSAGetLastError() << std::endl;
- break;
- }
-
- // Display received message and echo status
- WCHAR clientIp[INET_ADDRSTRLEN];
- InetNtop(AF_INET, &clientAddr.sin_addr, clientIp, INET_ADDRSTRLEN);
- std::wcout << L"Received: " << buffer << L" from " << clientIp << L":" << ntohs(clientAddr.sin_port) << std::endl;
- std::wcout << L"Echoed: " << buffer << L" to " << clientIp << L":" << ntohs(clientAddr.sin_port) << std::endl;
- }
-
- // Cleanup
- closesocket(serverSocket);
- WSACleanup();
- return 0;
- }
$ ~/bin/udp_sender 云主机的公网IP 14672 "Test UDP Echo Server"
UDP packet sent.
Received echoed UDP packet: Test UDP Echo Server
如果防火墙有重复的配置,需要删除
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。