简易端口扫描器

  在比较早以前,我用过S扫描器, 以及大名鼎鼎的nmap扫描器, 可以快速扫描某个主机开放的端口, 今天使用C实现这样一个软件,

  编译环境为Mac, 系统版本10.11.6:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h> void msg()
{
printf("EP:scan ip startport endport\nEP:scan ip 127.0.0.1 20 2009\n");
}
int main(int argc,char** argv)
{
char *ip;
int startport,endport,sockfd,i;
struct sockaddr_in to;
float costtime;
clock_t start,end;
if(!=argc)
{
msg();
return ;
}
ip=argv[];
startport=atoi(argv[]);
endport=atoi(argv[]);
if(startport< || endport> || endport<startport)
{
printf("端口范围出错/n");
return ;
}
else{
printf("IP:%s %d-%d\n",ip,startport,endport);
}
to.sin_family=AF_INET;
to.sin_addr.s_addr=inet_addr(ip);
start=clock();
for(i=startport;i<=endport;i++)
{
sockfd=socket(AF_INET,SOCK_STREAM,);
to.sin_port=htons(i);
if(connect(sockfd,(struct sockaddr *)&to,sizeof(struct sockaddr)) == ) {
printf("%s %d\n",ip,i);
close(sockfd);
};
}
end=clock();
costtime=(float)(end-start)/CLOCKS_PER_SEC;
printf("用时:%f秒\n",costtime);
return ;
}

  亲测可行:

  以上的代码只能检测固定的ip, 通过更改源码, 软件可以支持一段的ip端口检测, 多加一个循环:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include <sys/select.h>
#include <string>
void msg()
{
printf( "EP:scan ip startport endport\nEP:scan ip 127.0.0.1 20 2009\n" );
printf( "EP:scan ip endip startport endport\nEP:scan ip 127.0.0. 250 20 2009\n" );
}
void runsock(int sockfd, struct sockaddr_in to, char *ipval, int i) {
sockfd = socket( AF_INET, SOCK_STREAM, );
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
to.sin_port = htons( i );
//printf( "IP:%s %d\n", ipval, i );
if ( connect( sockfd, (struct sockaddr *) &to, sizeof(struct sockaddr) ) == ){
printf( "%s %d\n", ipval, i );
close( sockfd );
}
} int main( int argc, char* argv[] ){
char * ip;
char * endip;
int startport, endport, sockfd, i;
struct sockaddr_in to;
float costtime;
clock_t start, end;
if ( == argc ){
ip = argv[];
startport = atoi( argv[] );
endport = atoi( argv[] );
if ( startport < || endport > || endport < startport ){
printf( "端口范围出错/n" );
return();
}else{
printf( "IP:%s %d-%d\n", ip, startport, endport );
}
to.sin_family = AF_INET;
to.sin_addr.s_addr = inet_addr( ip );
start = clock();
for ( i = startport; i <= endport; i++ ){
runsock(sockfd, to, ip, i);
}
end = clock();
costtime = (float) (end - start) / CLOCKS_PER_SEC;
printf( "用时:%f秒\n", costtime );
return();
}else if ( == argc ){
ip = argv[];
endip = argv[];
startport = atoi( argv[] );
endport = atoi( argv[] );
char *tempip;
if ( startport < || endport > || endport < startport ){
printf( "端口范围出错/n" );
return();
}else{
/* 循环ip地址 */
start = clock();
char ipval[];
for ( int j = ; j <= atoi( endip ); j++ ){
sprintf( ipval, "%s%d", ip, j );
printf( "IP:%s\n", ipval );
to.sin_family = AF_INET;
to.sin_addr.s_addr = inet_addr( ipval );
for ( i = startport; i <= endport; i++ ){
runsock(sockfd, to, ipval, i);
}
}
end = clock();
costtime = (float) (end - start) / CLOCKS_PER_SEC;
printf( "用时:%f秒\n", costtime );
};/* 循环端口 */
return();
}
msg();
return();
}

  局域网网段IP端口扫描器

  看起来这个扫描器是实现了, 但是还有一个天大的问题, 那就是connect是同步的, 如果有些ip是不存在的, 那么connect函数就会阻塞在那边, 导致运行非常缓慢,那就需要异步的socket连接, 涉及select.h, 通过icmp判断存活主机:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h> #define PACKET_SIZE 4096 /* 计算校验和的算法 */
unsigned short cal_chksum(unsigned short *addr,int len)
{
int sum=;
int nleft = len;
unsigned short *w = addr;
unsigned short answer = ;
/* 把ICMP报头二进制数据以2字节为单位累加起来 */
while(nleft > ){
sum += *w++;
nleft -= ;
}
/*
* 若ICMP报头为奇数个字节,会剩下最后一字节。
* 把最后一个字节视为一个2字节数据的高字节,
* 这2字节数据的低字节为0,继续累加
*/
if(nleft == ){
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer; /* 这里将 answer 转换成 int 整数 */
}
sum = (sum >> ) + (sum & 0xffff); /* 高位低位相加 */
sum += (sum >> ); /* 上一步溢出时,将溢出位也加到sum中 */
answer = ~sum; /* 注意类型转换,现在的校验和为16位 */
return answer;
}
int livetest(char* ip) { char sendpacket[PACKET_SIZE]; /* 发送的数据包 */
char recvpacket[PACKET_SIZE]; /* 接收的数据包 */
pid_t pid;
int datalen = ; /* icmp数据包中数据的长度 */
struct protoent *protocol;
protocol = getprotobyname("icmp");
int sockfd;
int size = *;
if((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < ) {
perror("socket error");
}
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size) ); struct sockaddr_in dest_addr;
bzero(&dest_addr, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr(ip);
//send packet;
int packsize;
struct icmp *icmp;
struct timeval *tval;
icmp = (struct icmp*)sendpacket;
icmp->icmp_type = ICMP_ECHO; /* icmp的类型 */
icmp->icmp_code = ; /* icmp的编码 */
icmp->icmp_cksum = ; /* icmp的校验和 */
icmp->icmp_seq = ; /* icmp的顺序号 */
icmp->icmp_id = pid; /* icmp的标志符 */
packsize = + datalen; /* icmp8字节的头 加上数据的长度(datalen=56), packsize = 64 */
tval = (struct timeval *)icmp->icmp_data; /* 获得icmp结构中最后的数据部分的指针 */
gettimeofday(tval, NULL); /* 将发送的时间填入icmp结构中最后的数据部分 */
icmp->icmp_cksum = cal_chksum((unsigned short *)icmp, packsize);/*填充发送方的校验和*/ if(sendto(sockfd, sendpacket, packsize, , (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < ){
perror("sendto error");
}
//printf("send %d, send done\n",1 );
int n;
struct sockaddr_in from;
int fromlen = sizeof(from);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
struct timeval timeo = {,};
fd_set set;
FD_ZERO(&set);
FD_SET(sockfd, &set); //read , write;
int retval = select(sockfd+, &set, NULL, NULL, &timeo);
if(retval == -) {
printf("select error\n");
return ;
}else if(retval == ) {
//printf("timeout\n");
return ;
}else{
if( FD_ISSET(sockfd, &set) ){
//printf("host is live\n");
return ;
}
return ;
}
// n = recvfrom(sockfd, recvpacket,sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
// if(n<0) {
// perror("recvfrom error");
// }else{
// printf("%d\n",n);
// }
//return 0;
} static void sleep_ms(unsigned int secs){
struct timeval tval;
tval.tv_sec=secs/;
tval.tv_usec=(secs*)%;
select(,NULL,NULL,NULL,&tval);
} void msg()
{
printf( "EP:scan ip startport endport\nEP:scan ip 127.0.0.1 20 2009\n" );
printf( "EP:scan ip endip startport endport\nEP:scan ip 127.0.0. 1 250 20 2009\n" );
}
void runsock(int sockfd, struct sockaddr_in to, char *ipval, int i) {
sockfd = socket( AF_INET, SOCK_STREAM, );
fcntl(sockfd, F_SETFL, O_NONBLOCK);
fd_set set,writeSet;
int error; //错误代码
socklen_t len = sizeof(error);
//while(1){
FD_ZERO(&set);
FD_ZERO(&writeSet);
struct timeval timeo= {,};
//socklen_t len = sizeof(timeo);
FD_SET(sockfd,&set);
FD_SET(sockfd,&set);
//setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO,&timeo, len);
to.sin_port = htons( i );
//printf( "test %s %d , sockfd value %d\n", ipval, i , sockfd);
//printf( "IP:%s %d\n", ipval, i );
//printf("%d\n",i);
int conn = connect( sockfd, (struct sockaddr *) &to, sizeof(struct sockaddr) );
//等待
int retval = select(sockfd+ , &set, &writeSet, NULL, &timeo); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len );
if(error == )
printf("%s Port %d is opened\n", ipval, i);
//printf("%d\n",sockfd);
// printf("%s :%d\n",ipval, i);
// if (retval== -1) {
// perror("select error\n");
// } else if(retval == 0){
// //printf("timeout\n");
// }else{
// //printf("find %s :%d\n",ipval, i);
// if(FD_ISSET(sockfd,&set)) {
// printf("find %s :%d\n",ipval, i);
// }
// }
//}
} int main( int argc, char* argv[] ){
char * ip;
int endip, startip;
int startport, endport, sockfd, i;
struct sockaddr_in to;
float costtime;
clock_t start, end;
if ( == argc ){
ip = argv[];
startport = atoi( argv[] );
endport = atoi( argv[] );
if ( startport < || endport > || endport < startport ){
printf( "端口范围出错/n" );
return();
}else{
printf( "IP:%s %d-%d\n", ip, startport, endport );
}
to.sin_family = AF_INET;
to.sin_addr.s_addr = inet_addr( ip );
start = clock();
for ( i = startport; i <= endport; i++ ){
//printf("%d\n",i);
runsock(sockfd, to, ip, i);
}
end = clock();
costtime = (float) (end - start) / CLOCKS_PER_SEC;
printf( "用时:%f秒\n", costtime );
return();
}else if ( == argc ){
ip = argv[];
startip = atoi(argv[]);
endip = atoi(argv[]);
startport = atoi( argv[] );
endport = atoi( argv[] );
char *tempip;
if ( startport < || endport > || endport < startport ){
printf( "端口范围出错/n" );
return();
}else{
/* 循环ip地址 */
start = clock();
char ipval[];
for ( int j = startip; j <= endip ; j++ ){
sprintf( ipval, "%s%d", ip, j );
printf( "IP:%s\n", ipval );
if(livetest(ipval) == ){
to.sin_family = AF_INET;
//printf("okokok\n");
to.sin_addr.s_addr = inet_addr( ipval );
for ( i = startport; i <= endport; i++ ){
runsock(sockfd, to, ipval, i);
sleep_ms();
}
}
}
end = clock();
costtime = (float) (end - start) / CLOCKS_PER_SEC;
printf( "用时:%f秒\n", costtime );
};
//while(1){}
/* 循环端口 */
return();
}
msg();
return();
}

  使用方式1: scan ip startport endport

sudo ./s 192.168.2.114 1  139

  使用方式2: scan ip start endip startport endport

sudo ./s 192.168.1. 108 110 1 200

  还有一个问题, 就是扫描的端口不怎么准确, 经常出现误报, 有些端口跟没开, 但是扫描器会显示目标端口有开, 应该是判断sock是否连接成功的逻辑有问题, 目前没有好的解决方案, 期待大神指点一下:

    getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len );
if(error == )
printf("%s Port %d is opened\n", ipval, i);

  参考链接

    Linux C语言写的超级简单端口扫描器    http://blog.csdn.net/kongjiajie/article/details/4799986

    Linux的SOCKET编程详解    http://blog.csdn.net/hguisu/article/details/7445768/

  EOF

作者: NONO
出处:http://www.cnblogs.com/diligenceday/

QQ:287101329

微信:18101055830

mac/unix系统:C++实现一个端口扫描器的更多相关文章

  1. java编写一个端口扫描器

    好久没写java了,学的时候,也没学习网络编程这一块,无意中看到了一本书,于是小小复习一下java,写个端口扫描器,玩玩吧,网上这种小公具有的是,就是自己无聊写着玩玩. 源代码如下: 共两个类,比较简 ...

  2. Golang 写一个端口扫描器

    前话 最近痴迷于Golang这个新兴语言,因为它是强类型编译型语言,可以直接编译成三大平台的二进制执行文件,可以直接运行无需其他依赖环境.而且Golang独特的goroutine使得多线程任务执行如n ...

  3. 【技术分享】手把手教你使用PowerShell内置的端口扫描器

    [技术分享]手把手教你使用PowerShell内置的端口扫描器 引言 想做端口扫描,NMAP是理想的选择,但是有时候NMAP并不可用.有的时候仅仅是想看一下某个端口是否开放.在这些情况下,PowerS ...

  4. MD5做为文件名。机器唯一码有电脑的CPU信息和MAC地址,这两个信息需要在linux或unix系统下才能获取吧。

    可以采用机器(电脑)唯一码 + 上传IP + 当前时间戳 + GUID ( + 随机数),然后MD5做为文件名.机器唯一码有电脑的CPU信息和MAC地址,这两个信息需要在linux或unix系统下才能 ...

  5. Python与Hack之window下运行带参数的Python脚本,实现一个简单的端口扫描器

    1.前提是:windows已经配置好Python的环境变量: 2.进入cmd命令行模式: **输入python命令,检测是否环境配置好:显示这样说明配置环境变量没问题 **用cd命令进入Python脚 ...

  6. 如何在unix系统中用别的用户运行一个程序?

    1.问题的缘由 实际开发系统的时候,经常需要用别的用户运行一个程序.比如,有些系统为保证系统安全,不允许使用root来运行.这里,我们总结了unix系统下如何解决这个问题的一些方法.同时,我们还讨论如 ...

  7. 用Python实现一个端口扫描,只需简单几步就好

    一.常见端口扫描的原理 0.秘密扫描 秘密扫描是一种不被审计工具所检测的扫描技术. 它通常用于在通过普通的防火墙或路由器的筛选(filtering)时隐藏自己. 秘密扫描能躲避IDS.防火墙.包过滤器 ...

  8. UNIX系统上的抓包工具tcpdump常用命令说明

    tcpdump 介绍 tcpdump采用命令行方式对接口的数据包进行筛选抓取,其丰富特性表现在灵活的表达式上. 不带任何选项的tcpdump,默认会抓取第一个网络接口,且只有将tcpdump进程终止才 ...

  9. Nginx实现多个站点使用一个端口(配置Nginx的虚拟主机)

    Nginx 是一个轻量级高性能的 Web 服务器, 并发处理能力强, 消耗资源小, 无论是静态服务器还是网站, Nginx 表现更加出色, 作为 Apache 的补充和替代使用率越来越高,目前很多大型 ...

随机推荐

  1. iOS设备后台播放音乐方法

    iOS设备后台播放音乐方法 1 在设置Capabliites中打开Background Modes,选择Audio And AirPlay 2 在控制viewDidLoad中添加下面代码 AVAudi ...

  2. Codeforces 4D Mysterious Present

    http://codeforces.com/contest/4/problem/D 题目大意: 给出n个信封,这n个信封有长和宽,给出卡片的尺寸,求取能够装入卡片的最长的序列,序列满足后一个的长和宽一 ...

  3. JavaScript中的Array对象

    1.创建Array对象创建Array对象的语法var 数组名 = new Array();定义数组之后,就需要向数组中添加元素,格式如下数组名[<下标>]=值: 2.Array对象属性Ar ...

  4. JVM基础和调优(一)

    最近的项目中,出现了内存和性能的问题,需要优化,所以趁着这个机会,把自己关于java虚拟机的东整理一下,不对的地方,欢迎指出. 数据类型,因为在java的优化的过程中,检测到的数据类型一般比较的基础, ...

  5. Java里的equals总结

    前段时间一直在工作中使用Java,由于有一些C++功底,于是简单看了一下Java相关的语法便开始编写代码,结果在创建一个自定义类,并将自定义类放入ArrayList中,之后查找ArrayList是否有 ...

  6. SRM 598 DIV1

    A 只有3种情况:200以上的单独装,3个100的装一起,某两个u,v装一起且u+v<=300, 所以做法是从大到小判断每个大小的最大能与它装一起的是谁,最后剩下100的特判. B 第一轮如果未 ...

  7. myeclipse实现Servlet实例(2) 继承GenericServet类实现,需要重写service方法

    1.在myeclipse新建web project,配置Tomcat(在myeclipse的Window--preferences) 2.然后在src新建servlet文件( 此处放在com.tsin ...

  8. Spring的工作原理核心组件和应用

    Spring框架 Spring 是管理多个java类的容器框架,注意是类不管理接口. Spring 的主要功能 Ioc 反转控制和 DI 依赖注入. 注入的方式可以是构造函数赋值也可以是 set方法赋 ...

  9. poj 3104 Drying(二分搜索之最大化最小值)

    Description It is very hard to wash and especially to dry clothes in winter. But Jane is a very smar ...

  10. 解决&nbsp在IE与firefox宽度不一致的问题

    浏览器默认不同的字体问题,字体分为“等宽”和“不等宽”字体,所以&nbsp在IE与firefox内间距是不等的.   解决办法:   body{font-family: 宋体, simsun; ...