基于连接时长监控的摩尔斯敲门(Morse Knocking)技术可行性问询
基于连接时长的"摩尔斯敲门"实现类似端口敲门的功能
当然可以!你提出的通过跟踪TCP连接的建立与关闭时长来实现身份验证或信号传递的思路,本质上是端口敲门(Port Knocking)的一种创意变体——把传统"按顺序敲击不同端口"的逻辑,换成了"按特定时长敲击同一个端口",用来传递摩尔斯码这类结构化信号完全可行,比如你说的SOS求救信号就非常适合这种方式。
核心逻辑说明
这个方案的核心是:
- 客户端按预设的时长规则,反复建立并快速关闭TCP连接(比如100ms对应摩尔斯码的"点",300ms对应"划")
- 服务器端监听目标端口,记录每个连接的建立时间和关闭时间,计算连接持续时长
- 服务器将收集到的时长序列转换成对应信号(比如把连续3个100ms识别为'S',3个300ms识别为'O'),匹配预设规则后触发相应动作(比如解锁内部服务、触发告警)
修正后的客户端示例代码(MSVC平台)
你提供的代码思路没问题,但有几个小bug需要修正(比如循环条件错误、switch缺少break),以下是修复后的版本:
// Morse Knocking - Connection Duration: 100ms = dot, 300ms = dash. #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <stdlib.h> #include <stdio.h> #pragma comment (lib, "Ws2_32.lib") #pragma warning(disable : 4996) #define dot 100 #define dash 300 int __cdecl main(int argc, char** argv) { SOCKET client_socket; const int SIZE = 3; // Morse code distress signal ...---... char morse[SIZE] = { 'S', 'O', 'S'}; WSADATA wsaData; // 初始化Winsock if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed: %d\n", WSAGetLastError()); return 1; } struct sockaddr_in server; server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(80); // 目标监听端口 for (int i = 0; i < SIZE; i++) { switch (morse[i]) { case 'S': // 3个点(100ms连接) for (int j = 0; j < 3; j++) { client_socket = socket(AF_INET, SOCK_STREAM, 0); if (client_socket == INVALID_SOCKET) { printf("Socket creation failed: %d\n", WSAGetLastError()); WSACleanup(); return 1; } // 建立连接 if (connect(client_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) { printf("Connect failed: %d\n", WSAGetLastError()); closesocket(client_socket); WSACleanup(); return 1; } Sleep(dot); closesocket(client_socket); // 点之间的间隔(可选,根据摩尔斯码规范,点划间隔为1个点时长) Sleep(dot); } break; // 必须添加break,否则会继续执行O的逻辑 case 'O': // 3个划(300ms连接) for (int j = 0; j < 3; j++) { client_socket = socket(AF_INET, SOCK_STREAM, 0); if (client_socket == INVALID_SOCKET) { printf("Socket creation failed: %d\n", WSAGetLastError()); WSACleanup(); return 1; } if (connect(client_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) { printf("Connect failed: %d\n", WSAGetLastError()); closesocket(client_socket); WSACleanup(); return 1; } Sleep(dash); closesocket(client_socket); // 划之间的间隔 Sleep(dot); } break; default: printf("Unknown morse character\n"); WSACleanup(); exit(0); } // 字符之间的间隔(摩尔斯码规范为3个点时长) Sleep(dot * 3); } WSACleanup(); return 0; }
服务器端实现思路
要让这个方案完整运行,服务器端需要做这些事:
- 用Winsock监听目标端口,循环接受客户端连接
- 对每个连接,在
accept时记录当前时间戳 - 当连接被客户端关闭时,再次记录时间戳,计算连接持续时长
- 把时长归类为"点"(比如80-120ms)或"划"(280-320ms),允许一定误差(避免网络延迟影响)
- 收集这些点/划序列,匹配预设的信号规则(比如
...---...对应SOS),匹配成功后执行对应操作
注意事项
- 网络延迟:实际环境中要考虑网络延迟,服务器端的时长判断需要留一定容错区间
- 隐蔽性:和传统端口敲门一样,这种方式的隐蔽性依赖于服务器不对外暴露监听端口的状态(比如不发送RST包给未授权连接)
- 误判风险:要避免随机短连接被误识别为有效信号,可以增加信号的复杂度(比如更长的序列)
内容的提问来源于stack exchange,提问作者vengy
相关产品推荐
相关产品推荐

