C 语言实现基于 Linux 的端口扫描程序

Socket 常用函数:

⑴int socket(int protofamily, int type, int protocol);
  • protofamily:即协议域,又称为协议族(family)。常用的协议族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
  • type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等
  • protocol:指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议
⑵int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • ①sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。
  • ②addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同。
  • ③addrlen:对应的是地址的长度。
⑶int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
⑷int close(int fd);

使用到的函数:

⑴网络字节序和主机字节序的转换。

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。接收主机如果是小端字节序的,要做字节序的转换。

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
⑵字符串转换成整型数。
#include <stdlib.h>
int atoi(const char *nptr);
⑶点分十进制的IP转换成长整数型数
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
⑷获取端口服务
struct servent
{
    char *s_name;//这个服务的名称
    char **s_aliases;//这个服务可能的别名
    int s_port;//这个服务可能的端口
    char *s_proto;//这个服务可能使用的协议
};
struct servent *getservbyport(int port,char *proto);
⑸获取时间
struct timeval
{
    time_t tv_sec; //秒 
    long tv_usec;//微秒
};
int gettimeofday(struct timeval *tv, struct timezone *tz)
⑹初始化函数
void *memset(void *s, int ch, size_t n);

作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。

代码实现

#include <stdio.h>
#include <netdb.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/socket.h>

void u_alarm_handler() {
}

int main(int argc, char *argv[]) {
    /*
    struct sockaddr_in {
        sa_family_t    sin_family; //address family: AF_INET 
        in_port_t      sin_port;   //port in network byte order
        struct in_addr sin_addr;   //internet address 
    char           sin_zero[8];  //不使用,一般用0填充
    };

    //Internet address.
    struct in_addr {
        uint32_t       s_addr;     //address in network byte order
    };
    */
    struct sockaddr_in locaaddr, servaddr;

    //获取服务
    struct servent *serv;

    //计时
    struct timeval start;
    struct timeval end;
    float diff = 0; 

    int sfd, count = 0, ret = 0; 
    int currentport, startport, endport;

/*  
    memset(&locaaddr, 0, sizeof(struct sockaddr_in));  //每个字节都用0填充
    locaaddr.sin_family = AF_INET;                     //使用IPv4地址
    locaaddr.sin_addr.s_addr = htonl(INADDR_ANY);      //inet_addr("127.0.0.1")
    locaaddr.sin_port = htons(56666);   
*/  

    //int atoi(const char *nptr);
    //功能是把字符串转换成整型数
    startport = atoi(argv[2]);
    endport = atoi(argv[3]);

    if(startport<1 || endport>65535 || endport<startport) {  
        printf("端口范围出错\n");  
        return 0;   
    }   

    gettimeofday(&start, NULL);

    printf(" PORT    STATE   SERVICE\n");

    for(currentport = startport; currentport <= endport; currentport++) {
        if( (sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
            printf("Socket Create Failed!\n");
        }
        
        memset(&servaddr, 0, sizeof(struct sockaddr_in));
        servaddr.sin_family = AF_INET;
    
        //in_addr_t inet_addr(const char* strptr);
        //功能是将一个点分十进制的IP转换成一个长整数型数
        servaddr.sin_addr.s_addr = inet_addr(argv[1]);
        //uint16_t htons(uint16_t hostshort);
        //功能是将一个无符号短整型数值转换为网络字节序
        servaddr.sin_port = htons(currentport);
        
        serv = getservbyport(servaddr.sin_port, "tcp");

        sigset (SIGALRM, u_alarm_handler);
        alarm(1);
        ret = connect(sfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
        alarm(0);
        sigrelse(SIGALRM);

        if(ret == 0) {
            if (serv != NULL)
                printf("%5d   Opened\t %s\n", currentport, serv->s_name);
            else
                printf("%5d   Opened\t Unknown\n", currentport);
        }
        else 
            count++;

        close(sfd);
                    
    }

    printf("Not shown: %d closed ports\n", count);

    gettimeofday(&end, NULL);
    diff = 1000000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);
    printf("Total time: %.2f seconds\n", diff/1000000);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hosealyu1996/p/10388628.html