devops icon indicating copy to clipboard operation
devops copied to clipboard

linux tcp/ip syn

Open heidsoft opened this issue 2 years ago • 0 comments

在Ubuntu中,你可以使用tcpdump工具来观察TCP SYN发送。以下是具体步骤:

  1. 打开终端。

  2. 使用以下命令来捕获SYN包:

sudo tcpdump -i <interface_name> 'tcp[13] & 2!=0'

在上述命令中,<interface_name>是你的网络接口名称,如eth0、wlan0等。'tcp[13] & 2!=0'是一个过滤器,它只会显示SYN包。

如果你想在C语言中自定义发送SYN包,你需要使用原始套接字(Raw Sockets)。以下是一个简单的例子:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>

// 这是一个伪头部,用于TCP校验和计算
struct pseudo_header
{
    unsigned int source_address;
    unsigned int dest_address;
    unsigned char placeholder;
    unsigned char protocol;
    unsigned short tcp_length;
};

unsigned short csum(unsigned short *ptr,int nbytes)
{
    register long sum;
    unsigned short oddbyte;
    register short answer;

    sum=0;
    while(nbytes>1) {
        sum+=*ptr++;
        nbytes-=2;
    }
    if(nbytes==1) {
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    }

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;
    
    return(answer);
}

int main (void)
{
    // 创建一个原始套接字
    int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
    
    // 一些地址结构
    char datagram[4096] , source_ip[32] , *data , *pseudogram;
    
    // 零化数据报
    memset (datagram, 0, 4096);
    
    // 你自己的IP
    strcpy(source_ip , "192.168.1.2");
    
    struct sockaddr_in sin;
    struct pseudo_header psh;
    
    // 数据部分
    data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
    strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    
    // IP头部
    struct iphdr *iph = (struct iphdr *) datagram;
    
    // TCP头部
    struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
    
    // 填充IP头部
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr) + strlen(data);
    iph->id = htonl (54321);
    iph->frag_off = 0;
    iph->ttl = 255;
    iph->protocol = IPPROTO_TCP;
    iph->check = 0;
    iph->saddr = inet_addr ( source_ip );
    iph->daddr = sin.sin_addr.s_addr;
    
    // TCP头部
    tcph->source = htons (1234);
    tcph->dest = htons (80);
    tcph->seq = 0;
    tcph->ack_seq = 0;
    tcph->doff = 5;
    tcph->syn = 1;
    tcph->window = htons (5840);
    tcph->check = 0;
    tcph->urg_ptr = 0;
    
    // IP校验和
    iph->check = csum ((unsigned short *) datagram, iph->tot_len);
    
    // 填充伪头部
    psh.source_address = inet_addr( source_ip );
    psh.dest_address = sin.sin_addr.s_addr;
    psh.placeholder = 0;
    psh.protocol = IPPROTO_TCP;
    psh.tcp_length = htons(20);
    
    int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
    pseudogram = malloc(psize);
    
    memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
    memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr));
    
    tcph->check = csum( (unsigned short*) pseudogram , psize);
    
    // 发送数据报
    if (sendto (s, datagram, iph->tot_len ,  0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
    {
        perror("sendto failed");
    }
    else
    {
        printf ("Packet Send. Length : %d \n" , iph->tot_len);
    }
    
    return 0;
}

这个程序会发送一个SYN包到目标IP和端口。请注意,这个程序需要以root权限运行,因为它使用了原始套接字。此外,你可能需要根据自己的环境进行一些调整。

这只是一个基本的示例,现实中你可能需要处理更多的细节,例如错误处理、超时、重试等。

在Ubuntu中,你可以使用tcpdump工具来观察TCP SYN发送。以下是具体步骤:

  1. 打开终端。

  2. 使用以下命令来捕获SYN包:

sudo tcpdump -i <interface_name> 'tcp[13] & 2!=0'

在上述命令中,<interface_name>是你的网络接口名称,如eth0、wlan0等。'tcp[13] & 2!=0'是一个过滤器,它只会显示SYN包。

如果你想在C语言中自定义发送SYN包,你需要使用原始套接字(Raw Sockets)。以下是一个简单的例子:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>

// 这是一个伪头部,用于TCP校验和计算
struct pseudo_header
{
    unsigned int source_address;
    unsigned int dest_address;
    unsigned char placeholder;
    unsigned char protocol;
    unsigned short tcp_length;
};

unsigned short csum(unsigned short *ptr,int nbytes)
{
    register long sum;
    unsigned short oddbyte;
    register short answer;

    sum=0;
    while(nbytes>1) {
        sum+=*ptr++;
        nbytes-=2;
    }
    if(nbytes==1) {
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    }

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;
    
    return(answer);
}

int main (void)
{
    // 创建一个原始套接字
    int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
    
    // 一些地址结构
    char datagram[4096] , source_ip[32] , *data , *pseudogram;
    
    // 零化数据报
    memset (datagram, 0, 4096);
    
    // 你自己的IP
    strcpy(source_ip , "192.168.1.2");
    
    struct sockaddr_in sin;
    struct pseudo_header psh;
    
    // 数据部分
    data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
    strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    
    // IP头部
    struct iphdr *iph = (struct iphdr *) datagram;
    
    // TCP头部
    struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
    
    // 填充IP头部
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr) + strlen(data);
    iph->id = htonl (54321);
    iph->frag_off = 0;
    iph->ttl = 255;
    iph->protocol = IPPROTO_TCP;
    iph->check = 0;
    iph->saddr = inet_addr ( source_ip );
    iph->daddr = sin.sin_addr.s_addr;
    
    // TCP头部
    tcph->source = htons (1234);
    tcph->dest = htons (80);
    tcph->seq = 0;
    tcph->ack_seq = 0;
    tcph->doff = 5;
    tcph->syn = 1;
    tcph->window = htons (5840);
    tcph->check = 0;
    tcph->urg_ptr = 0;
    
    // IP校验和
    iph->check = csum ((unsigned short *) datagram, iph->tot_len);
    
    // 填充伪头部
    psh.source_address = inet_addr( source_ip );
    psh.dest_address = sin.sin_addr.s_addr;
    psh.placeholder = 0;
    psh.protocol = IPPROTO_TCP;
    psh.tcp_length = htons(20);
    
    int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
    pseudogram = malloc(psize);
    
    memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
    memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr));
    
    tcph->check = csum( (unsigned short*) pseudogram , psize);
    
    // 发送数据报
    if (sendto (s, datagram, iph->tot_len ,  0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
    {
        perror("sendto failed");
    }
    else
    {
        printf ("Packet Send. Length : %d \n" , iph->tot_len);
    }
    
    return 0;
}

这个程序会发送一个SYN包到目标IP和端口。请注意,这个程序需要以root权限运行,因为它使用了原始套接字。此外,你可能需要根据自己的环境进行一些调整。

这只是一个基本的示例,现实中你可能需要处理更多的细节,例如错误处理、超时、重试等。

heidsoft avatar Oct 13 '23 15:10 heidsoft