#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>
extern int h_errno;
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
\
}while(0)
//设置socket非阻塞
void active_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
ERR_EXIT("fcntl");
flags |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -1)
ERR_EXIT("fcntl");
}
//设置socket阻塞
void deactive_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
ERR_EXIT("de-fcntl");
flags &= ~O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -1)
ERR_EXIT("de-fcntl");
}
//利用select异步IO模型设置connect函数超时,优化扫描时间
int conn_timeout(int fd, struct sockaddr_in *addr, long wait_second)
{
//socklen_t addrlen = sizeof(struct sockaddr_in);
active_nonblock(fd);
int rc = connect(fd, (struct sockaddr*)&(*addr), sizeof(*addr));
if (rc != 0)
{
if (errno == EINPROGRESS)
{
//printf("Doing connection.\n");
/*正在处理连接*/
fd_set fdr, fdw;
FD_ZERO(&fdr);
FD_ZERO(&fdw);
FD_SET(fd, &fdr);
FD_SET(fd, &fdw);
struct timeval timeout;
timeout.tv_usec = wait_second;
timeout.tv_sec = 0;
rc = select(fd + 1, &fdr, &fdw, NULL, &timeout);
//printf("rc is: %d\n", rc);
/*select调用失败*/
if (rc < 0)
{
//fprintf(stderr, "connect error:%s\n", strerror(errno));
deactive_nonblock(fd);
close(fd);
return -1;
}
/*连接超时*/
if (rc == 0)
{
//fprintf(stderr, "Connect timeout.\n");
deactive_nonblock(fd);
close(fd);
return -1;
}
/*[1] 当连接成功建立时,描述符变成可写,rc=1*/
if (rc == 1 && FD_ISSET(fd, &fdw))
{
//printf("Server Port %d Open!\n",port);
deactive_nonblock(fd);
close(fd);
return 0;
}
/*[2] 当连接建立遇到错误时,描述符变为即可读,也可写,rc=2 遇到这种情况,可调用getsockopt函数*/
if (rc == 2)
{
int err;
int errlen = sizeof(err);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)
{
//fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));
deactive_nonblock(fd);
close(fd);
return -1;
}
if (err)
{
errno = err;
//fprintf(stderr, "connect error:%s\n", strerror(errno));
deactive_nonblock(fd);
close(fd);
return -1;
}
}
}
fprintf(stderr, "connect failed, error:%s.\n", strerror(errno));
return -1;
}
return 0;
//deactive_nonblock(sockfd);
}
//将域名转化为IP
const char *getIPAddrbyHostname(const char * hostname)
{
static char s[128];
memset(s,0,sizeof(s));
struct hostent *h;
h = gethostbyname(hostname);
if ( h == NULL )
{
printf("Unkown Domain: %s\n",strerror(h_errno));
return NULL;
}
strcpy(s, inet_ntoa(*((struct in_addr*)h->h_addr)));
return s;
}
int main(int argc, char* argv[])
{
if (argc < 4 )
{
printf("Usage:%s [Dst-Ip|Domain] [Start-Port] [End-Port]\n", argv[0]);
return 1;
}
int i;
const char *ipaddr = getIPAddrbyHostname(argv[1]);
if( ipaddr == NULL )
{
puts("A Error Occured, The Program Quit!\n");
return 1;
}
struct timeval start,end;
gettimeofday(&start, NULL);
for (i = atoi(argv[2]); i <= atoi(argv[3]); i++)
{
int sockfd = 0;
//建立socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("create socket failed");
return 1;
}
//connect 连接server
struct sockaddr_in serveraddr_in;
memset(&serveraddr_in, 0, sizeof(serveraddr_in));
serveraddr_in.sin_family = AF_INET;
serveraddr_in.sin_port = htons(i); /* port in network byte order */
serveraddr_in.sin_addr.s_addr = inet_addr(ipaddr);
if ( conn_timeout(sockfd, &serveraddr_in, 100000) == 0)
{
printf("Host %s Tcp Port \033[33m%5d \033[0mOpening.\n", argv[1], i);
}
}
gettimeofday(&end, NULL);
int total = (int)(end.tv_sec - start.tv_sec);
printf("\nScan Cost Time: \033[31;5m %d \033[0m min \033[31;5m%d\033[0m sec\n", total/60, total%60);
return 0;
}
/**************与本项目无关代码******************/
/*
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nread = read(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nread == 0) //若对方已关闭
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nwritten = write(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nwritten == 0)
continue;
bufp += nwritten;
nleft -= nwritten;
}
return count;
}
ssize_t recv_peek(int sockfd, void *buf, ssize_t len)
{
while (1)
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == -1 && errno == EINTR)
{
continue;
}
return ret;
}
}
ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while (1)
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < 0)
return ret;
else if (ret == 0)
return ret;
nread = ret;
int i;
for (i = 0; i < nread; ++i)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i + 1);
if ( ret != (i + 1))
exit(EXIT_FAILURE);
return ret;
}
}
if (nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -1;
}
void echo_cli (int conn)
{
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
{
writen(conn, sendbuf, strlen(sendbuf));
int ret = readline(conn, recvbuf, 1024);
if (ret == -1)
ERR_EXIT("readline failed\n");
if (ret == 0)
{
printf("server close\n");
break;
}
fputs(recvbuf, stdout);
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
}
}
*/
/*--------------------UDP Scan Test-----------------------------*/
/*
for (i = atoi(argv[2]); i <= atoi(argv[3]); i++)
{
int sockfd = 0;
//建立socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("create socket failed");
return 1;
}
struct sockaddr_in serveraddr_in;
memset(&serveraddr_in, 0, sizeof(serveraddr_in));
serveraddr_in.sin_family = AF_INET;
serveraddr_in.sin_port = htons(i);
serveraddr_in.sin_addr.s_addr = inet_addr(argv[1]);
//udp也可以使用connect函数,引用来维持一个状态信息
connect(sockfd, (struct sockaddr*)&serveraddr_in, sizeof(serveraddr_in));
//①调用了connect指定了地址,sendto可简写:sendto(sockfd,sendbuf,sizeof(sendbuf),0,NULL,0)
//②一旦调用了connect,可以使用send函数:send(sockfd,sendbuf,sizeof(sendbuf),0)
sendto(sockfd,"hello",sizeof("hello"),0,
(struct sockaddr *)&serveraddr_in,sizeof(serveraddr_in));
char recvbuf[1024] = {0};
int rc = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, NULL, NULL);
if ( rc == -1 )
{
//printf("Server %s Ucp Port %d opening ...\n", argv[1], i);
perror("recvfrom:");
}
}
*/
🔗
备份地址: 【基于Linux的Tcp端口扫描器的实现】