在网络安全和系统管理中,检测TCP服务器是否正在监听特定端口是一项常见任务。本文将介绍一个基于C语言实现的TCP服务器监听检测工具的原理、相关技术和实现细节。
概述
该工具通过发送TCP连接请求来检测目标服务器是否在指定端口上监听。它支持IPv4和IPv6,并允许用户自定义连接超时和等待超时时间。工具的核心功能包括:
- 检测TCP服务器是否监听特定端口。
- 支持非阻塞连接和超时机制。
- 提供灵活的命令行选项配置。
技术原理
1. TCP三次握手
TCP连接的建立基于三次握手过程:
如果服务器正在监听目标端口,它会响应SYN-ACK包;否则,连接将失败或超时。
2. 非阻塞连接
非阻塞套接字允许程序在发起连接后立即返回,而无需等待连接完成。这使得程序可以在连接过程中执行其他任务,提高效率。
3. poll机制
poll系统调用用于监控文件描述符的状态(如是否可读、可写或出错)。在本工具中,poll用于检测套接字是否准备好进行数据传输或是否存在错误。
TCP服务器监听状态检测原理与实现技术(C/C++代码实现)
int scanfix(char *s, uint64_t *result, int scale)
{
...
while (*s) {
if ((unsigned)(*s)–'0' < 10) {
if (r <= UINT64_MAX/10 && 10*r <= UINT64_MAX–((*s)–'0'))
r = r*10 + ((*s)–'0');
else
return –ERANGE;
} else if (*s == '.') {
if (d)
return –EINVAL;
d = s + 1;
} else {
return –EINVAL;
}
s++;
}
if (!d)
d = s;
int o = scale – (int)(s–d);
for (; o > 0; o—) {
if (r > UINT64_MAX/10)
return –ERANGE;
r *= 10;
}
for (; o < 0; o++) {
if (r % 10 != 0)
return –ERANGE;
r /= 10;
}
*result = r;
return 0;
}
int
syn_scan(struct addrinfo *addr)
{
int sock = socket(addr->ai_family,
addr->ai_socktype | SOCK_NONBLOCK,
addr->ai_protocol);
struct linger l = {1, 0};
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&l, sizeof (struct linger));
int zero = 0;
setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, (void *)&zero, sizeof zero);
int r;
errno = 0;
r = connect(sock, addr->ai_addr, addr->ai_addrlen);
if (r > 0 || errno != EINPROGRESS) {
fprintf(stderr, "connect failed: %m\\n");
close(sock);
return 99;
}
struct pollfd fds[1];
fds[0] = (struct pollfd){ sock, POLLIN | POLLOUT | POLLERR, 0 };
r = poll(fds, 1, connect_timeout);
if (r == 0) {
printf("timeout");
return 2;
} else if (r != 1) {
printf("??? poll = %d %m\\n", r);
close(sock);
return 99;
}
...
return 99;
}
int
main(int argc, char *argv[])
{
...
while ((c = getopt(argc, argv, "+46t:w:")) != –1) {
switch (c) {
case '4': protocol = 4; break;
case '6': protocol = 6; break;
case 't':
if ((err = scanfix(optarg, &connect_timeout, 3)) < 0) {
fprintf(stderr, "failed to parse number '%s': %s\\n",
optarg, strerror(–err));
goto usage;
}
break;
case 'w':
if ((err = scanfix(optarg, &wait_timeout, 9)) < 0) {
fprintf(stderr, "failed to parse number '%s': %s\\n",
optarg, strerror(–err));
goto usage;
}
break;
default:
usage:
fprintf(stderr,
"Usage: %s [-w WAIT_TIMEOUT] [-t CONNECT_TIMEOUT] [HOST] PORT\\n",
argv[0]);
return 99;
}
}
struct addrinfo hints = {
.ai_socktype = SOCK_STREAM,
}, *res;
...
clock_gettime(CLOCK_MONOTONIC, &now);
deadline.tv_sec = now.tv_sec;
deadline.tv_nsec = now.tv_nsec + wait_timeout;
if (deadline.tv_nsec >= 1000000000L) {
deadline.tv_sec += deadline.tv_nsec / 1000000000L;
deadline.tv_nsec = deadline.tv_nsec % 1000000000L;
}
...
while (now.tv_sec < deadline.tv_sec ||
(now.tv_sec == deadline.tv_sec && now.tv_nsec <= deadline.tv_nsec)) {
switch (syn_scan(res)) {
case 0:
return 0;
case 99:
return 99;
case 1:
nanosleep(&delay, 0); // avoid busy wait
}
clock_gettime(CLOCK_MONOTONIC, &now);
}
return 2;
}
If you need the complete source code, please add the WeChat number (c17865354792)
1. 命令行参数解析
工具通过getopt函数解析命令行参数,支持以下选项:
- -4:强制使用IPv4。
- -6:强制使用IPv6。
- -t:设置连接超时时间(单位:毫秒)。
- -w:设置等待超时时间(单位:纳秒)。
2. 地址解析
使用getaddrinfo函数将目标主机名和端口解析为套接字地址结构(struct addrinfo)。该函数支持IPv4和IPv6地址,并允许指定地址族和套接字类型。
3. 非阻塞连接
通过socket函数创建非阻塞套接字,并使用connect函数发起连接请求。如果连接成功或处于进行中状态,connect将返回特定值。
4. 超时处理
工具使用poll监控套接字状态,并根据用户指定的超时时间决定是否继续等待。如果连接超时或失败,工具将输出相应信息并退出。
5. 等待机制
如果用户指定了等待超时时间(-w选项),工具将在指定时间内反复尝试连接目标服务器。每次尝试之间会使用nanosleep函数引入延迟,避免频繁尝试。
应用场景
该工具适用于以下场景:
- 网络安全扫描:检测目标服务器的开放端口。
- 服务监控:检查关键服务是否正常运行。
- 自动化测试:验证网络服务的可用性。
总结
本文介绍了基于C语言实现的TCP服务器监听检测工具的原理和实现细节。通过非阻塞连接、poll机制和灵活的超时配置,该工具能够高效地检测目标服务器的监听状态。它在网络管理、安全检测和自动化测试中具有广泛的应用价值。
Welcome to follow WeChat official account【程序猿编码】
评论前必须登录!
注册