mac/unix系统:C++实现一个端口扫描器
简易端口扫描器
在比较早以前,我用过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++实现一个端口扫描器的更多相关文章
- java编写一个端口扫描器
好久没写java了,学的时候,也没学习网络编程这一块,无意中看到了一本书,于是小小复习一下java,写个端口扫描器,玩玩吧,网上这种小公具有的是,就是自己无聊写着玩玩. 源代码如下: 共两个类,比较简 ...
- Golang 写一个端口扫描器
前话 最近痴迷于Golang这个新兴语言,因为它是强类型编译型语言,可以直接编译成三大平台的二进制执行文件,可以直接运行无需其他依赖环境.而且Golang独特的goroutine使得多线程任务执行如n ...
- 【技术分享】手把手教你使用PowerShell内置的端口扫描器
[技术分享]手把手教你使用PowerShell内置的端口扫描器 引言 想做端口扫描,NMAP是理想的选择,但是有时候NMAP并不可用.有的时候仅仅是想看一下某个端口是否开放.在这些情况下,PowerS ...
- MD5做为文件名。机器唯一码有电脑的CPU信息和MAC地址,这两个信息需要在linux或unix系统下才能获取吧。
可以采用机器(电脑)唯一码 + 上传IP + 当前时间戳 + GUID ( + 随机数),然后MD5做为文件名.机器唯一码有电脑的CPU信息和MAC地址,这两个信息需要在linux或unix系统下才能 ...
- Python与Hack之window下运行带参数的Python脚本,实现一个简单的端口扫描器
1.前提是:windows已经配置好Python的环境变量: 2.进入cmd命令行模式: **输入python命令,检测是否环境配置好:显示这样说明配置环境变量没问题 **用cd命令进入Python脚 ...
- 如何在unix系统中用别的用户运行一个程序?
1.问题的缘由 实际开发系统的时候,经常需要用别的用户运行一个程序.比如,有些系统为保证系统安全,不允许使用root来运行.这里,我们总结了unix系统下如何解决这个问题的一些方法.同时,我们还讨论如 ...
- 用Python实现一个端口扫描,只需简单几步就好
一.常见端口扫描的原理 0.秘密扫描 秘密扫描是一种不被审计工具所检测的扫描技术. 它通常用于在通过普通的防火墙或路由器的筛选(filtering)时隐藏自己. 秘密扫描能躲避IDS.防火墙.包过滤器 ...
- UNIX系统上的抓包工具tcpdump常用命令说明
tcpdump 介绍 tcpdump采用命令行方式对接口的数据包进行筛选抓取,其丰富特性表现在灵活的表达式上. 不带任何选项的tcpdump,默认会抓取第一个网络接口,且只有将tcpdump进程终止才 ...
- Nginx实现多个站点使用一个端口(配置Nginx的虚拟主机)
Nginx 是一个轻量级高性能的 Web 服务器, 并发处理能力强, 消耗资源小, 无论是静态服务器还是网站, Nginx 表现更加出色, 作为 Apache 的补充和替代使用率越来越高,目前很多大型 ...
随机推荐
- z-index 所遇问题
document.getElementById('wx_share_img').style.cssText = "width:100%;height:100%;position:fixed; ...
- ural 1586. Threeprime Numbers
这道题看着别人的代码写的. #include <cstdio> #include <cstring> #define m 1000000009 using namespace ...
- 编译Qt 4.7.3的时候发生NMAKE : fatal error U1077: 'cd' : return code '0x2'
怀疑是configure的时候没加-nomake demos -nomake examples的问题 references: http://stackoverflow.com/questions/10 ...
- 安卓,通过本地应用分享到微信、facebook等
别的不说了,直接上代码. 支持分享到微信.微博.facebook.twitter package com.example.shareSample; import java.util.List; imp ...
- 关于bootstrap--表格(tr的各种样式)
只需要<tr class="active">就可以用active样式. 特别提示:除了”.active”之外,其他四个类名和”.table-hover”配合使用时,Bo ...
- poj 3273 Monthly Expense(二分搜索之最大化最小值)
Description Farmer John ≤ moneyi ≤ ,) that he will need to spend each day over the next N ( ≤ N ≤ ,) ...
- 利用libevent的timer实现定时器interval
在不怎么了解libevent的情况下,看到timer这个关键字想到可以用来做定时任务,官方资料也不齐全,就从代码里看到了TIMEOUT字样,这么说来应该是支持timeout了,那interval呢,貌 ...
- pyqt托盘例子
# -*- coding: cp936 -*- #!/usr/bin/env python # -*- coding:utf-8 -*- from PyQt4 import QtCore, QtGui ...
- JavaScript函数 bind call apply区别
1. apply calll 在JavaScript中 call 和 apply 都是为了改变某个函数运行时上下文而存在的, 换句话说就是为了改变函数内部的this的指向. 这里我们有一个新的对象 b ...
- keepalived vip漂移基本原理及选举算法
keepalived可以将多个无状态的单点通过虚拟IP(以下称为VIP)漂移的方式搭建成一个高可用服务,常用组合比如 keepalived+nginx,lvs,haproxy和memcached等.它 ...