我正在使用套接字编写一个简单的tcp服务器应用程序。据我所知,我可以在调用accept()后获取客户端的IP地址和端口。
现在假设我有一个banlist,我想从我的服务器上禁用一些ip地址。有没有比接受连接然后丢弃它更好的方法?
在接受连接之前,有没有办法获取客户端的IP和端口?如果我们接受()为什么我们没有像垃圾()那样的东西?有没有办法拒绝连接或只是忽略来自主机的连接尝试?
答案 0 :(得分:13)
TCP实现通常在用户进程甚至可以访问连接之前完成TCP 3次握手,而accept()
函数只是从队列中获取下一个连接。因此,假装服务器已关闭已为时已晚。这对于常规TCP数据的工作方式相同;在TCP ACK发送之前,TCP实现不会等待应用程序实际recv()
数据。这使得另一方不必要地重新传输正确接收的数据包,并允许吞吐量保持高,即使应用程序被其他东西陷入困境。在新连接(SYN数据包)的情况下,这也允许内核保护自己(和应用程序)免受SYN泛洪攻击。
虽然不可移植,但许多平台提供某种防火墙功能,允许根据IP地址/端口过滤传入连接。但是,这通常是在系统范围内配置的,而不是由单个应用程序配置的。
答案 1 :(得分:4)
在 windows 上:查看WSAAccept,可能是您需要的:
SOCKET WSAAccept(
__in SOCKET s,
__out struct sockaddr *addr,
__inout LPINT addrlen,
__in LPCONDITIONPROC lpfnCondition,
__in DWORD dwCallbackData
);
lpfnCondition - 可选的,应用程序指定的条件函数的地址,它将根据作为参数传入的调用者信息做出接受/拒绝决定,并可选择通过为其分配适当的值来创建或加入套接字组。该函数的结果参数g。如果此参数为NULL,则不调用条件函数。
对于 linux 解决方案,请看:GNU Common C ++ - TCPSocket类,它有onAccept()和reject()方法。
virtual bool TCPSocket::onAccept ( const InetHostAddress & ia,
tpport_t port
) [inline, protected, virtual]
调用派生的TCPSocket类的方法,该类在接受连接请求时充当服务器。
服务器可以实现协议特定规则,以通过返回false来排除远程套接字被接受。 Peek方法也可用于此目的。
但是,如果前置条件为假,您可以在接受后关闭套接字:)
答案 2 :(得分:1)
TCP Wrapper在类UNIX平台上变得非常普遍。是的,仅在 accept
之后检查连接;但是,如果你正在这样做,你也可以使用与其他人一样的配置。
从本质上讲,您的程序可以使用tcpd
运行,也可以直接修改为使用libwrap
,如下所示:
#include <tcpd.h>
connfd = accept(listenfd, (struct sockaddr *)&addr, &addrlen);
if (!hosts_ctl("my_program", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), STRING_UNKNOWN)) {
fprintf(stderr, "Client %s connection disallowed\n", inet_ntoa(addr.sin_addr));
close(connfd);
}
然后根据您的要求配置/etc/hosts.allow
和/etc/hosts.deny
,例如
# /etc/hosts.allow my_program: 127.0.0.1 10. 192.168. # /etc/hosts.deny my_program: ALL
这会导致my_program
拒绝来自非本地地址的所有连接尝试,但可以在不触及my_program
的情况下进行更改。
答案 3 :(得分:-1)
如果您正在使用NAT,则不接受基于IP地址的连接的概念将无效。