【问题标题】:Implement TCP hand shake in C用C实现TCP握手
【发布时间】:2014-12-07 00:42:58
【问题描述】:

我已经使用 TCP 原始套接字来实现简单的 TCP 握手,以便创建一个简单的端口扫描器,在这个端口扫描器中,我想遵循半开放的方法。正如我们所知,在这种方法中,我们首先向远程主机发送一个 SYN 数据包,然后:

  • 如果主机以 SYN/ACK 响应,则该端口已打开,我们应该重置连接。
  • 如果主机响应 RST,则该端口已关闭,我们就完成了。
  • 如果主机没有响应,那么我们可以认为端口被过滤了。

我已经完成了这种方法的实现。但我认为我的代码有问题。例如,当我向 Web 服务器的端口 80 发送 SYN 时,它会使用 RST 数据包重置连接

谁能指出我的代码有什么错误?提前致谢

请注意,我使用 ubuntu 14.04 作为操作系统,使用 eclipse 作为 IDE

int scan(char *hostip, int port){
    // file descriptor for the socket
    int fd;
    // tcp header length
    int tcphdr_len = sizeof(struct tcphdr);
    // buffers containing raw packets
    char send_buffer[PACKET_LENGTH], recv_buffer[PACKET_LENGTH];
    // tcp header segment of raw packet
    struct tcphdr *tcp = (struct tcphdr *) send_buffer;
    // address of the destination entry point
    struct sockaddr_in addr;
    // size of received packet
    int recvd_size;
    int one = 1, result;

    // clearing whole of the packet
    memset(send_buffer, 0, PACKET_LENGTH);
    memset(recv_buffer, 0, PACKET_LENGTH);
    // creating raw socket
    fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if(fd < 0){
       die("failed to create socket");
    }
    // address family
    addr.sin_family = AF_INET;
    // destination port
    addr.sin_port = htons(port);
    // destination ip
    addr.sin_addr.s_addr = inet_addr(hostip);

    // the tcp structure
    // source port
    tcp->source = htons(12345);
    // destination port
    tcp->dest = addr.sin_port;
    tcp->seq = htonl(1);
    tcp->doff = 5;
    tcp->syn = 1;
    tcp->window = htons(65535);

    if(sendto(fd, send_buffer, tcphdr_len, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0){
       die("sendto failed");
    }

    recvd_size = recvfrom(fd, recv_buffer, PACKET_LENGTH, 0, 0, 0);
    if(recvd_size < 0){ // error occurred
        close(fd);
        die("failed to receive packet");
    }
    if(recvd_size == 0){ // timed out
        close(fd);
        return ST_FILTERED;
    }
    result = process_packet(recv_buffer, recvd_size);
    if(result == PCK_UNKNOWN){
        close(fd);
        return ST_UNKNOWN;
    }
    if(result == PCK_RST){
        close(fd);
        return ST_CLOSED;
    }

    close(fd);
    return ST_OPEN;
}

这里是函数process_packet

int process_packet(char *buffer, int size){
    struct tcphdr *tcp = (struct tcphdr *) buffer;
    fprintf(stdout, "\nsport=%i\ndport=%i\nsyn=%i\nack=%i\nrst=%i\nrecv size=%i\n", ntohs(tcp->source),
            ntohs(tcp->dest),
            tcp->syn,
            tcp->ack,
            tcp->rst,
            size);
    if(tcp->syn & tcp->ack){
        return PCK_SYN_ACK;
    }
    if(tcp->rst){
        return PCK_RST;
    }
    return PCK_UNKNOWN;
}

这是我的./myprg -t 81.31.160.39程序的输出

target=81.31.160.39 *** port=80 *** status=
sport=17664
dport=1400
syn=0
ack=0
rst=1
recv size=1024
closed

目标端口也应该是 12345 但不是。

【问题讨论】:

  • @nos 哎呀!我忘了设置 TCP 校验和,我收到的数据包是一个 ICMP 数据包,表明主机不可达。无论如何谢谢。

标签: c linux tcp raw-sockets


【解决方案1】:

您最好查看wireshark 中的数据包,并尝试找出哪些字段有误。

但是documentation 说:

用于接收的IP头总是包含在数据包中。

这意味着接收到的数据以 IP 标头开头,您的 process_packet() 必须在到达 tcp 标头之前对其进行解析。

【讨论】:

  • 哦,你是对的,总是包含 IP 标头。在您非常有帮助的帮助下,我解决了我的问题。我真诚地感谢您的提示。
猜你喜欢
  • 2012-04-06
  • 1970-01-01
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多