jjzjj

c - Linux C 原始套接字 TCP 握手

coder 2023-09-18 原文

我正在尝试使用 C 中的原始套接字(在 Debian 系统上)创建 TCP 连接,但我很难让它工作。它会发送一个数据包,但我没有收到服务器的任何响应。我已经测试并将该数据包与从 nmap 发送的数据包进行比较,我看不出有任何重大差异。

这是服务器端收到的TCP数据包,服务器端从不发送SYN ACK数据包(我在服务器端使用Wireshark进行监控)

No.     Time           Source                Destination           Protocol Length Info
     75 1.893700000    192.168.1.129         192.168.1.114         TCP      74         56540→445 [SYN] Seq=0 Win=1024 Len=0 MSS=1460 SACK_PERM=1 WS=128 TSval=863195 TSecr=0

Frame 75: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface 0
Ethernet II, Src: Vmware_77:f0:a0 (00:0c:29:77:f0:a0), Dst: IntelCor_07:f9:e5     (e8:b1:fc:07:f9:e5)
Internet Protocol Version 4, Src: 192.168.1.129 (192.168.1.129), Dst: 192.168.1.114 (192.168.1.114)
Version: 4
Header Length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
Total Length: 60
Identification: 0xb88d (47245)
Flags: 0x00
Fragment offset: 0
Time to live: 255
Protocol: TCP (6)
Header checksum: 0x7eea [validation disabled]
Source: 192.168.1.129 (192.168.1.129)
Destination: 192.168.1.114 (192.168.1.114)
[Source GeoIP: Unknown]
[Destination GeoIP: Unknown]
Transmission Control Protocol, Src Port: 56540 (56540), Dst Port: 445 (445), Seq: 0, Len: 0
Source Port: 56540 (56540)
Destination Port: 445 (445)
[Stream index: 3]
[TCP Segment Len: 0]
Sequence number: 0    (relative sequence number)
Acknowledgment number: 0
Header Length: 40 bytes
.... 0000 0000 0010 = Flags: 0x002 (SYN)
Window size value: 1024
[Calculated window size: 1024]
Checksum: 0x7ff8 [validation disabled]
Urgent pointer: 0
Options: (20 bytes), Maximum segment size, SACK permitted, Window scale, No-Operation (NOP), Timestamps
    Maximum segment size: 1460 bytes
        Kind: Maximum Segment Size (2)
        Length: 4
        MSS Value: 1460
    TCP SACK Permitted Option: True
        Kind: SACK Permitted (4)
        Length: 2
    Window scale: 7 (multiply by 128)
        Kind: Window Scale (3)
        Length: 3
        Shift count: 7
        [Multiplier: 128]
    No-Operation (NOP)
        Type: 1
    Timestamps: TSval 863195, TSecr 0
        Kind: Time Stamp Option (8)
        Length: 10
        Timestamp value: 863195
        Timestamp echo reply: 0

0000  e8 b1 fc 07 f9 e5 00 0c 29 77 f0 a0 08 00 45 00   ........)w....E.
0010  00 3c b8 8d 00 00 ff 06 7e ea c0 a8 01 81 c0 a8   .<......~.......
0020  01 72 dc dc 01 bd db 0f 13 02 00 00 00 00 a0 02   .r..............
0030  04 00 7f f8 00 00 02 04 05 b4 04 02 03 03 07 01   ................
0040  08 0a 00 0d 2b db 00 00 00 00                     ....+.....

这是我的代码,我知道它很乱,我只是想学习如何使用原始套接字

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

struct ipheader {
 unsigned char          iph_ihl:4, /* Little-endian */
                        iph_ver:4;
 unsigned char          iph_tos;
 unsigned short int     iph_len;
 unsigned short int     iph_ident;
 unsigned short int     iph_offset:13,  /* Little-endian*/
                        iph_flags:3;
 unsigned char          iph_ttl;
 unsigned char          iph_protocol;
 unsigned short int     iph_chksum;
 unsigned int           iph_sourceip;
 unsigned int           iph_destip;
};

struct tcpheader {
 u_int16_t      tcph_srcport;
 u_int16_t      tcph_destport;
 u_int32_t      tcph_seqnum;
 u_int32_t      tcph_acknum;
 u_int16_t
                tcph_ns:1,
                tcph_reserved:3,
                tcph_offset:4,
                tcph_fin:1,
                tcph_syn:1,
                tcph_rst:1,
                tcph_psh:1,
                tcph_ack:1,
                tcph_urg:1,
                tcph_ece:1,
                tcph_cwr:1;
 u_int16_t      tcph_win;
 u_int16_t      tcph_chksum;
 u_int16_t      tcph_urgptr;
};

struct tcpheaderOptions
{

    u_int16_t 
        tcph_mssOpt:8,
        tcph_mssLen:8;
    u_int16_t
        tcph_mss;
    u_int16_t
        tcph_sack:8,
        tcph_sackLen:8;
    u_int16_t
        tcph_winOpt:8,
        tcph_winLen:8;
    u_int32_t
        tcph_win:8,
        tcph_winNOP:8,
        tcph_timeOpt:8,
        tcph_timeLen:8;
    u_int32_t tcph_time;
    u_int32_t tcph_timeEcho;
};

unsigned short          /* this function generates header checksums */
csum (unsigned short *buf, int nwords)
{
  unsigned long sum;
  for (sum = 0; nwords > 0; nwords--)
    sum += *buf++;
  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  return ~sum;
}



int main(void)
{
  char datagram[4096];
  char data[] = "Hello my name is Keith, this is my first packet";
  memset(datagram,0,4096);
  struct ipheader *IPInfo = (struct ipheader *) datagram;
  struct tcpheader *TCPHeader = (struct tcpheader *) (datagram + sizeof(struct ipheader));
  struct tcpheaderOptions *TCPOptions = (struct tcpheaderOptions *) (datagram + sizeof(struct tcpheader) + sizeof(struct ipheader));
  struct sockaddr_in sin;               //Te destination
  sin.sin_family = AF_INET;
  sin.sin_port = htons(4);
  sin.sin_addr.s_addr = inet_addr("192.168.1.114");

  IPInfo->iph_ver       = 4;            //What IP version are we using? v4
  IPInfo->iph_ihl       = 5;            //The IP header size in bytes
  IPInfo->iph_tos       = 0;            //The IP header type of service 0x00 is normal
  IPInfo->iph_len       = sizeof(struct ipheader) + sizeof(struct tcpheader) + sizeof(struct tcpheaderOptions);            //The IP length of the IP datagram
  IPInfo->iph_ident     = htonl(54321);         //The IP header ID (used when fragmented)
  IPInfo->iph_offset    = 0;            //IP fragment offset
  IPInfo->iph_ttl       = 255;          //The IP TTL
  IPInfo->iph_protocol          = 6;            //The transport layer protocol (6 for TCP, 1 for ICMP, 17 for UDP)
  IPInfo->iph_chksum    = 0;            //Checksum
  IPInfo->iph_sourceip  = inet_addr("192.168.1.129"); //source
//  IPInfo->iph_destip = sin.sin_addr.s_addr;
  IPInfo->iph_destip    = inet_addr("192.168.1.114");
char source[20];
char dest[20];
inet_ntop(AF_INET, &(IPInfo->iph_sourceip), source, 20);
inet_ntop(AF_INET, &(IPInfo->iph_destip), dest, 20);
printf("Source: %s\n", source);
printf("Dest: %s\n", dest);
  //IPInfo->ip_dst.s_addr       = inet_addr("192.168.1.114");
  TCPHeader->tcph_srcport       = htons(56540);           //The source port
  TCPHeader->tcph_destport      = htons(445);          //The destination port
  srand(time(NULL));
  TCPHeader->tcph_seqnum        = rand();          //the sequence number
  TCPHeader->tcph_acknum        = 0;                 //ACK packet
  TCPHeader->tcph_reserved      = 0;                    //Not used
  TCPHeader->tcph_offset        = 10;                 //
  TCPHeader->tcph_cwr           = 0;
  TCPHeader->tcph_ns            = 0;
  TCPHeader->tcph_syn           = 1;
  TCPHeader->tcph_rst           = 0;
  TCPHeader->tcph_psh           = 0;
  TCPHeader->tcph_ack           = 0;
  TCPHeader->tcph_urg           = 0;
  TCPHeader->tcph_ece           = 0;
  TCPHeader->tcph_cwr           = 0;
  TCPHeader->tcph_ns            = 0;
  TCPHeader->tcph_win           = htons(1024);
  TCPHeader->tcph_chksum        = 0;
  TCPHeader->tcph_urgptr        = 0;
  TCPOptions->tcph_mssOpt       = 2;
  TCPOptions->tcph_mssLen       = 4;
  TCPOptions->tcph_winOpt       = 3;
  TCPOptions->tcph_winLen       = 3;
  TCPOptions->tcph_sack         = 4;
  TCPOptions->tcph_sackLen      = 2;
  TCPOptions->tcph_win          = 7;
  TCPOptions->tcph_winNOP       = 1;
  TCPOptions->tcph_mss          = htons(1460);
  TCPOptions->tcph_timeOpt      = 8;
  TCPOptions->tcph_timeLen      = 10;
  TCPOptions->tcph_time         = 0xdb2b0d00;
  //Adding the data
  //strcpy(datagram + sizeof(struct ipheader) + sizeof(struct tcpheader),data);
  TCPHeader->tcph_chksum = csum((unsigned short *) datagram,TCPHeader->tcph_offset >> 1);
  IPInfo->iph_chksum = csum((unsigned short *) datagram, IPInfo->iph_len >> 1);


  int sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
  if(sockfd == -1) {
    perror("sockfd");
    exit(1);
  }

  //Setting IP_HDRINCL so that the system doesnt add headers to my packets
  {
    int one = 1;
    const int *val = &one;
    if(setsockopt(sockfd,IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
      perror("setsockopt");
      return -1;
    }
    else
      printf("Using your own header\n");
  }
  //Creating a raw socket to send info on
    if(sendto(sockfd, datagram, IPInfo->iph_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
      perror("send");
    else
      printf("sending\n");

  printf("Sent sequence number: %d\n",TCPHeader->tcph_seqnum);

        //Now we will wait to receive a message back
        memset(datagram,0,4096);
        int results = recv(sockfd,datagram,sizeof(datagram),0);
        printf("Results: %d\n",results);
        IPInfo = (struct ipheader *) datagram;
        TCPHeader = (struct tcpheader * ) (datagram + (IPInfo->iph_ihl * 4));
        printf("Packet: IPInfo->iph_ihl %d\n",IPInfo->iph_ihl);
        printf("ACK num = %d\n",TCPHeader->tcph_ack);

char source1[20];
char dest1[20];
inet_ntop(AF_INET, &(IPInfo->iph_sourceip), source, 20);
inet_ntop(AF_INET, &(IPInfo->iph_destip), dest, 20);    

    printf("Source: %s\n",source1);
    printf("Dest: %s\n",dest1);

    printf("Size of ipheader %d\n",sizeof(struct ipheader));
    printf("size of tcpheader %d\n",sizeof(struct tcpheader));

  return 0;
}

最佳答案

在 wireshark 中启用校验和验证,这样您至少可以确定您没有计算错误的校验和(在 IP 或 TCP header 中)– nos

谢谢,我的 TCP 校验和无效 – Keith

关于c - Linux C 原始套接字 TCP 握手,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27630216/

有关c - Linux C 原始套接字 TCP 握手的更多相关文章

  1. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  2. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  3. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  4. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  5. ruby - 从 ruby​​ block 更改原始变量? - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:'passparameterbyreference'inRuby?在这个例子中:deftestverb='nothing'yieldverbputsverbendtest{|verb|verb='something'}它将打印“无”。是否可以将其更改为“某物”?谢谢

  6. ruby - 为什么 String::sub!() 会更改 Ruby 中克隆对象的原始对象? - 2

    我的Ruby代码中有一个看起来有点像这样的结构Parameter=Struct.new(:name,:id,:default_value,:minimum,:maximum)稍后,我使用创建了这个结构的一个实例freq=Parameter.new('frequency',15,1000.0,20.0,20000.0)在某些时候,我需要这个结构的精确副本,所以我调用newFreq=freq.clone然后,我更改newFreq的名称newFreq.name.sub!('f','newF')奇迹般地,它也改变了freq.name!像newFreq.name='newFrequency'这样

  7. ruby - 使用 ruby​​ 进行套接字编程是个好主意吗? - 2

    我选择的语言是Ruby,但因为Twitter,我知道Ruby不能处理很多请求。将它用于套接字开发是个好主意吗?或者我应该像Twitter开发人员那样使用像erlang或haskell或scala这样的函数式语言吗? 最佳答案 我工作的公司使用Ruby作为我们的网站。到目前为止,我们已经处理了超过34,000,000,000次点击。我们每天处理大约10,000,000次点击没有问题。每天的点击量峰值已超过40,000,000次。可扩展性取决于很多因素。例如,与读取相比,我们的数据库执行的写入比例高得不成比例。虽然大多数网站执行大约90

  8. ruby - 重新连接 tcpsocket(或如何检测已关闭的套接字) - 2

    我有一个连接到服务器的ruby​​tcpsocket客户端。在发送数据之前如何检查套接字是否已连接?我是否尝试“拯救”断开连接的tcpsocket,重新连接然后重新发送?如果是这样,有没有人有一个简单的代码示例,因为我不知道从哪里开始:(我很自豪我设法在rails中获得了一个持久连接的客户端tcpsocket。然后服务器决定杀死客户端,一切都崩溃了;)编辑我已经使用此代码解决了一些问题-如果未连接,它将尝试重新连接,但如果服务器已关闭则不会处理这种情况(它将继续重试)。这是正确方法的开始吗?谢谢defself.write(data)begin@@my_connection.write(

  9. ruby - 如何从 Rack 获取原始格式的请求 header ? - 2

    我正在尝试使用Ruby从Rack获取原始格式的请求header,但还没有弄清楚。我从request.env得到的散列不是我想要的。在该散列中,header键被大写并使用下划线而不是破折号,如下所示:"CONTENT_TYPE"=>"应用程序/json;字符集=utf-8"我想要的是处理前的header,我正在寻找:"Content_Type"=>"application/json;charset=utf-8"我可以很容易地循环遍历request.env寻找以HTTP_开头的header并将它们拆分,将每个单词和gsub大写以将下划线替换为破折号以使它们成为我想要的格式。在处理标题时,以

  10. ruby-on-rails - Rails 是否支持监听 UDP 套接字的简洁方式? - 2

    在Rails中,什么是集成更新模型某些元素的UDP监听过程的最佳方式(特别是它将向其中一个表添加行)。简单的答案似乎是在同一个进程中使用UDP套接字对象启动一个线程,但我什至不清楚我应该在哪里做适合Rails方式的事情。有没有一种巧妙的方法来开始收听UDP?具体来说,我希望能够编写一个UDPController并在每个数据报消息上调用一个特定的方法。理想情况下,我希望避免在UDP上使用HTTP(因为它会浪费一些在这种情况下非常宝贵的空间),但我完全控制消息格式,因此我可以为Rails提供它需要的任何信息。 最佳答案 Rails是一个

随机推荐