简易端口扫描器

  在比较早以前,我用过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. 使用GCD的dispatch_once创建单例

    使用GCD的dispatch_once创建单例 介绍了创建单例的方式,不过后来发现其实在ios 4.0后有更加简单的方式. 就是使用GCD的功能 代码如下: + (instantClass *)sha ...

  2. 关于MPLS协议几个容易忽略的点

    1.随着硬件技术的进步,产生了高速路由器和三层交换机,MPLS提高转发的速度的初衷已经没有多少意义.但是MPLS由于其支持标签栈和面向连接的特点,使其在虚拟专用网,流量工程,QoS等方面得到广泛的应用 ...

  3. Android获取当前时间与星期几

    public class DataString { private static String mYear; private static String mMonth; private static ...

  4. scheme 解释器Guile 使用

    GNU Guile是一种Scheme编程语言的解释器和虚拟机.Guile是GNU Ubiquitous Intelligent Language for Extensions的缩写.Guile是GNU ...

  5. Java里的equals总结

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

  6. 关于Java集合的总结

    (一)List: ArrayList 以数组实现.节约空间,但数组有容量限制.超出限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值.默认第一 ...

  7. 专题笔记--Java 类集框架

    Java 类集框架 1. Java类集框架产生的原因 在基础的应用中,我们可以通过数组来保存一组对象或者基本数据,但数组的大小是不可更改的,因此出于灵活性的考虑和对空间价值的担忧,我们可以使用链表来实 ...

  8. hdu 5072 Coprime (容斥)

    Problem Description There are n people standing in a line. Each of them has a unique id number. Now ...

  9. Laravel Eloquent ORM

    Eloquent ORM 简介 基本用法 集体赋值 插入.更新.删除 软删除 时间戳 查询范围 关系 查询关系 预先加载 插入相关模型 触发父模型时间戳 与数据透视表工作 集合 访问器和调整器 日期调 ...

  10. iphone开发 IOS 组织架构图

    转载自 :http://blog.csdn.net/mashi321323/article/details/18267719   登录|注册     mashi321323的专栏       目录视图 ...