原理:connect()函数用于对于每一个感兴趣的目标计算机的端口进行连接,如果该端口处于侦听状态,那么connect()就会成功,即没有提供服务。如果对于每一个目标端口以串行的方式使用单独的connect()调用,需要较长的时间,我们可以通过使用非阻塞I/O设置一个较低的时间周期或者同时观察多个套接字来提高扫描速度。
这个程序实现的是扫描局域网中其他主机的IP并输出主机名和对应主机开启的端口,我获取局域网中其他主机的地址的方法是通过读取ARP缓存表,这样好像有点偷懒的嫌疑,哈哈。
环境:kali linux+gcc 6.xx
#include<stdio.h>
#include<sys/socket.h>
#include<errno.h>
#include<ctype.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>#define MAX 65535
#define THREAD_NUM 50typedef struct IP_Message{int MinPort;int MaxPort;struct in_addr ip;
}IP_Message;void *scan(void *arg){IP_Message *IP_M;char ipaddress[36];int i;int net;int err;struct hostent *host;struct sockaddr_in sa;int ret;fd_set wset;fd_set rset;int sel;//se:lectint flags;int get;//getsockoptint error=0;socklen_t len=sizeof(error);struct timeval tval;tval.tv_sec=1;tval.tv_usec=0;IP_M=arg;memset(&sa,0,sizeof(struct sockaddr_in));sa.sin_family=AF_INET;sa.sin_addr.s_addr=IP_M->ip.s_addr;for(i=1;i<1025;i++){sa.sin_port=htons(i);if((net=socket(AF_INET,SOCK_STREAM,0))<0){perror("\nsocket");exit(2);}flags=fcntl(net,F_GETFL,0);//鑾峰彇鏂囦欢鐨刦lags鍊?fcntl(net,F_SETFL,flags|O_NONBLOCK);//璁剧疆鎴愰潪闃诲妯″紡ret=connect(net,(struct sockaddr*)&sa,sizeof(sa));if(ret==0){printf("%s %-5d\n",inet_ntoa(sa.sin_addr),i);close(net);}else{if(errno==EINPROGRESS){FD_ZERO(&wset);FD_ZERO(&rset);FD_SET(net,&wset);FD_SET(net,&rset);sel=select(net+1,&rset,&wset,NULL,&tval);if(sel<=0||sel==2){close(net);}else if(sel==1&&FD_ISSET(net,&wset)){printf("%s %-5d Opened!\n",inet_ntoa(sa.sin_addr),i);close(net);}else{close(net);}}}}
}void mul_scan(char *arg){int i;struct hostent *he;printf("%s :",arg);pthread_t worker_tid;IP_Message IP;IP.ip.s_addr=inet_addr(arg);he=gethostbyaddr((char *)&IP.ip.s_addr,sizeof(struct in_addr),AF_INET);if(he!=NULL)printf("%s\n",he->h_name); elseprintf("\n");if(pthread_create(&worker_tid,NULL,scan,(void *)&IP)!=0){perror("create:");exit(1);}pthread_join(worker_tid,NULL);
}int main(){char ip[16];char buffer[100];FILE *fp;fp=fopen("/proc/net/arp","r");if(!fp){perror("fp");exit(2);}fgets(buffer,100,fp);while(!feof(fp)){fgets(ip,16,fp);if(feof(fp))break;mul_scan(ip);fgets(buffer,100,fp);}fclose(fp);return 0;
}
较为可惜的是因为时间原因没有实现多线程同时观察多个套接字。