Bootstrap

端口详解+端口扫描原理+简单端口扫描实现

一 摘要

        端口是个网络应用中很重要的东西,相当于“门”。
二 什么是端口
        端口在计算机网络中是个非常重要的概念,他不是硬件,不同于计算机中的插槽,可以说是个软插槽。如果有需要,一台计算机中可以由上万个端口。 

       端口是由计算通信协议TCP/IP协议定义的。其中规定,用IP地址和端口作为套接字,它代表TCP链接的一个连接端,一般称为socket,具体来说,就是用[ip:端口]来定位一台主机中的进程。可以做这样的比喻,端口相当于两台计算机进程间的大门,可随便定义,其目的只是为了让两台计算机能找到对方的进程。计算机就想一座大楼,这个大楼有好多入口(端口),进到不同的入口中就可以找到不同的公司(进程)。如果要和远程主机A的程序通信,那么只要把数据发向[A;端口]就可以实现通信了。
三 端口的分类
  在Internet上,按照协议类型分类,端口被分为TCP端口和UDP端口两类,虽然他们都用正整数标识,但这并不会引起歧义,比如TCP的80端口和UDP的80端口,因为数据报在标明端口的同时,还将标明端口的类型。 
  从端口的分配来看,端口被分为固定端口和动态端口两大类(一些教程还将极少被用到的高端口划分为第三类:私有端口):
  固定端口(0-1023):
   使用集中式管理机制,即服从一个管理机构对端口的指派,这个机构负责发布这些指派。由于这些端口紧绑于一些服务,所以我们会经常扫描这些端口来判断对方 是否开启了这些服务,如TCP的21(ftp),80(http),139(netbios),UDP的7(echo),69(tftp)等等一些大家熟 知的端口;
  动态端口(1024-49151):
  这些端口并不被固定的捆绑于某一服务,操作系统将这些端口动态的分配给各个进程, 同一进程两次分配有可能分配到不同的端口。不过一些应用程序并不愿意使用操作系统分配的动态端口,他们有其自己的‘商标性’端口,如oicq客户端的 4000端口,木马冰河的7626端口等都是固定而出名的。

四 端口在入侵中的作用
  有人曾经把服务器比作房子,而把端口比作通向不同房间(服务)的门,如果不考虑细节的话,这是一个不错的比喻。入侵者要占领这间房子,势必要破门而入(物理入侵另说),那么对于入侵者来说,了解房子开了几扇门,都是什么样的门,门后面有什么东西就显得至关重要。
   入侵者通常会用扫描器对目标主机的端口进行扫描,以确定哪些端口是开放的,从开放的端口,入侵者可以知道目标主机大致提供了哪些服务,进而猜测可能存在 的漏洞,因此对端口的扫描可以帮助我们更好的了解目标主机,而对于管理员,扫描本机的开放端口也是做好安全防范的第一步。

五、端口扫描原理:尝试与目标主机建立连接,如果目标主机有回复则说明端口开放。
扫描分类:
      1. 全TCP连接,这种方法使用三次握手与目标主机建立标准的tcp连接。但是这种方法跟容易被发现,被目标主机记录。
      2. SYN扫描,扫描主机自动向目标主机的指定端口发送SYN数据段,表示发送建立连接请求。
!!如果目标主机的回应报文SYN=1,ACK=1.则说明该端口是活动的,接着扫描主机发送回一个RST给目标主机拒绝连接。导致三次握手失败。
!!如果目标主机回应是RST则端口是“死的”。
      3 FIN扫描,发送一个FIN=1的报文到一个关闭的窗口该报文将丢失并返回一个RST,如果该FIN报文发送到活动窗口则报文丢失,不会有任何反应。
      4.代理扫描。就是抓鸡啦。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <pthread.h>

#define MAX_THREAD_NUM 100
#define SEG_LEN 655
#define MAX_PORT 65535

typedef struct PortNode
{
    char ip[30];
    int minPort;
    int maxPort;
}PortNode;
pthread_t tid;
void* doit(void* arg)
{
    int i, sockfd, connfd;
    struct sockaddr_in servaddr;
    PortNode* port = (PortNode*)arg;
    pthread_detach(pthread_self());//为避免存储器泄漏,每个可结合线程都应该被其他线程显式地收回,要么通过调用pthread_detach函数被分离
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    //inet_pton(AF_INET, port->ip, &servaddr.sin_addr);
    servaddr.sin_addr.s_addr = inet_addr(port->ip);
    for(i = port->minPort; i <= port->maxPort; i++){
        servaddr.sin_port = htons(i);
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
            perror("socket error");
            pthread_exit(NULL);
        }
        if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == 0){
            printf("%s:%d\n", port->ip, i);
        }
        close(sockfd);//注意关闭!!
    }
    pthread_exit(NULL);
}


int main(int argc, char** argv)
{
    int i,j;
    for(i = 1; i < argc; i++){
        PortNode* port = (PortNode*)malloc(sizeof(PortNode));
        for(j = 0; j < MAX_THREAD_NUM; j++){
            strcpy(port->ip, argv[i]);
            port->minPort = j*SEG_LEN + 1;
            if(j == (MAX_THREAD_NUM - 1))port->maxPort = MAX_PORT;
            else port->maxPort = port->minPort + SEG_LEN - 1;
            if(pthread_create(&tid, NULL, doit, (void*) port)  != 0 ){
                perror("pthread create error.\n");
                free(port);
                port=NULL;
                exit(1);
            }
        }
    }
    sleep(3);
}


;