我正在尝试使用 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/
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
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()还是其他方法完成
一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我
我有一个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
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:'passparameterbyreference'inRuby?在这个例子中:deftestverb='nothing'yieldverbputsverbendtest{|verb|verb='something'}它将打印“无”。是否可以将其更改为“某物”?谢谢
我的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'这样
我选择的语言是Ruby,但因为Twitter,我知道Ruby不能处理很多请求。将它用于套接字开发是个好主意吗?或者我应该像Twitter开发人员那样使用像erlang或haskell或scala这样的函数式语言吗? 最佳答案 我工作的公司使用Ruby作为我们的网站。到目前为止,我们已经处理了超过34,000,000,000次点击。我们每天处理大约10,000,000次点击没有问题。每天的点击量峰值已超过40,000,000次。可扩展性取决于很多因素。例如,与读取相比,我们的数据库执行的写入比例高得不成比例。虽然大多数网站执行大约90
我有一个连接到服务器的rubytcpsocket客户端。在发送数据之前如何检查套接字是否已连接?我是否尝试“拯救”断开连接的tcpsocket,重新连接然后重新发送?如果是这样,有没有人有一个简单的代码示例,因为我不知道从哪里开始:(我很自豪我设法在rails中获得了一个持久连接的客户端tcpsocket。然后服务器决定杀死客户端,一切都崩溃了;)编辑我已经使用此代码解决了一些问题-如果未连接,它将尝试重新连接,但如果服务器已关闭则不会处理这种情况(它将继续重试)。这是正确方法的开始吗?谢谢defself.write(data)begin@@my_connection.write(
我正在尝试使用Ruby从Rack获取原始格式的请求header,但还没有弄清楚。我从request.env得到的散列不是我想要的。在该散列中,header键被大写并使用下划线而不是破折号,如下所示:"CONTENT_TYPE"=>"应用程序/json;字符集=utf-8"我想要的是处理前的header,我正在寻找:"Content_Type"=>"application/json;charset=utf-8"我可以很容易地循环遍历request.env寻找以HTTP_开头的header并将它们拆分,将每个单词和gsub大写以将下划线替换为破折号以使它们成为我想要的格式。在处理标题时,以
在Rails中,什么是集成更新模型某些元素的UDP监听过程的最佳方式(特别是它将向其中一个表添加行)。简单的答案似乎是在同一个进程中使用UDP套接字对象启动一个线程,但我什至不清楚我应该在哪里做适合Rails方式的事情。有没有一种巧妙的方法来开始收听UDP?具体来说,我希望能够编写一个UDPController并在每个数据报消息上调用一个特定的方法。理想情况下,我希望避免在UDP上使用HTTP(因为它会浪费一些在这种情况下非常宝贵的空间),但我完全控制消息格式,因此我可以为Rails提供它需要的任何信息。 最佳答案 Rails是一个