看UNIX编程中关于select调用中的拒绝服务攻击

jody_go 2013-03-19 09:08:43
服务端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <sys/sendfile.h>
#include <strings.h>
#include <fcntl.h>

#define SERV_PORT 8889 /* 服务器监听端口号 */


//设置socket连接为非阻塞模式
void setnonblocking(int sockfd)
{
int opts;

opts = fcntl(sockfd, F_GETFL);
if(opts < 0) {
perror("fcntl(F_GETFL)\n");
exit(1);
}
opts = (opts | O_NONBLOCK);
if(fcntl(sockfd, F_SETFL, opts) < 0) {
perror("fcntl(F_SETFL)\n");
exit(1);
}
}

int main(int argc, char *argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int rtn = 0;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rest, allrest;
socklen_t clilen;
char buf[128];
struct sockaddr_in cliaddr, servaddr;

memset(buf, 0, sizeof(buf));

listenfd = socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);

rtn = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (rtn)
{
printf("bind err!\n");
exit(-1);
}

listen(listenfd, 20);

maxfd = listenfd;
maxi = -1;
for (i = 0; i < FD_SETSIZE; i++)
{
client[i] = -1;
}

FD_ZERO(&allrest);
FD_SET(listenfd, &allrest); /* 告诉内核,我们需要对哪些描述字进行测试 */

for (; ;)
{
rest = allrest;

nready = select(maxfd+1, &rest, NULL, NULL, NULL);

if (FD_ISSET(listenfd, &rest)) /* 返回后, rest结构中的内容被重写,任何未就绪的描述字被置为0 */
{
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);

//setnonblocking(connfd); //设置为非阻塞

printf("new socket accept, connfd = %d\n", connfd);

for (i=0; i < FD_SETSIZE; i++)
{
if (client[i] < 0)
{
client[i] = connfd;
break;
}
}

if (i == FD_SETSIZE)
return -1;

FD_SET(connfd, &allrest);
if (connfd > maxfd)
maxfd = connfd;

if (i > maxi)
maxi = i;

if (--nready <= 0)
{
continue;
}
}

for (i = 0; i <= maxi; i++)
{
if ((sockfd = client[i]) < 0)
continue;

if (FD_ISSET(sockfd, &rest))
{
/*接受来自客户端的信息*/
if ((n = Readline(sockfd, (char *)buf, sizeof(buf))) == 0)
{
close(sockfd);
FD_CLR(sockfd, &allrest);
client[i] = -1;
}
else if (n > 0)
{
/*处理信息,并发送给具体的服务进行业务逻辑处理*/
printf("form client : %s[%d]\n", buf, n);
strcat(buf, "_server");

/*返回客户端处理结果*/
writen(sockfd, buf, sizeof(buf));
}
else if (n == -1)
{
printf("%s\n",strerror(errno));
}

if (--nready <= 0)
break;
}
}
}
}


/*自定制的read函数*/
ssize_t Readline(int fd, void *buf, size_t num)
{
ssize_t res;
size_t n;
char *ptr;

n = num;
ptr = (char *)buf;
while (n > 0)
{
if ((res = read(fd, ptr, n)) == -1)
{
if (errno == EINTR) /*中断*/ //非阻塞应该考虑 errno == EWOULDBLOCK || errno == EAGAIN?
res = 0;
else if (errno == ECONNRESET)
return 0;
else
{
return -1;
}
}
else if (res == 0)
break;

ptr += res;
n -= res;
}

return (num - n);
}

/*自定制的write函数*/
ssize_t writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;

ptr = (char *)vptr;
nleft = n;

while (nleft > 0)
{
if ((nwritten = write(fd, ptr, nleft)) <= 0)
{
if (nwritten < 0 && errno == EINTR) //非阻塞应该考虑 errno == EWOULDBLOCK || errno == EAGAIN
{
nwritten = 0;
}
else
{ printf("%s\n",strerror(errno));
return -1;
}
}
nleft -= nwritten;
ptr += nwritten;
}

return n;
}


客服端:

int main(int argc, char *argv[])
{
int server;
int maxfd = 0;
ssize_t n;
char buf[128];
struct sockaddr_in sin;
struct hostent *host;
int clientmsgtype;

server = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(SERVPORT);
sin.sin_addr.s_addr = inet_addr("192.168.159.132");

if (connect (server, (struct sockaddr*)&sin, sizeof(sin))<0)
{
printf("connect err\n");
exit(1);
}

buf[0] = 'a';
write (server, &buf, sizeof(buf));

if ((n = read(server, (char *)buf, sizeof(buf))) > 0)
{
printf("%s\n", buf);
}

return 0;
}


服务端接受一个socket连接后,阻塞于Readline函数处,当客服端只发送一个字符时,服务端就会一直阻塞在
Readline函数,而无法对其它用户提供服务。若是设置为setnonblocking(connfd);非阻塞模式,则Readline函数该如何编写呢?
...全文
46 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

23,114

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧