我正在连接linux / tcp.h,而我试图阅读TCP选项,我似乎无法找到如何做到这一点。我在线阅读了一些内容,根据一些在线消息来源,我必须迭代所有剩余的数据包"直到我点击我想要的选项? (现在我将尝试专注于" MSS"选项)。任何人都可以为我提供代码示例吗?
struct iphdr *iph = ((struct iphdr *) full_packet);
fprintf(stdout, "IP{v=%u; ihl=%u; tos=%u; tot_len=%u; id=%u; ttl=%u; protocol=%u; "
,iph->version, iph->ihl*4, iph->tos, ntohs(iph->tot_len), ntohs(iph->id), iph->ttl, iph->protocol);
if (iph->protocol == 6){
struct tcphdr *tcp = ((struct tcphdr *) (full_packet + (iph->ihl << 2)));
fprintf(stdout, "TCP{sport=%u; dport=%u; seq=%u; ack_seq=%u; flags=u%ua%up%ur%us%uf%u; window=%u; urg=%u}\n",
ntohs(tcp->source), ntohs(tcp->dest), ntohl(tcp->seq), ntohl(tcp->ack_seq)
,tcp->urg, tcp->ack, tcp->psh, tcp->rst, tcp->syn, tcp->fin, ntohs(tcp->window), tcp->urg_ptr);\
}
到目前为止,我在阅读/解析IP / TCP数据方面是什么
谢谢!
Bump ...感谢任何帮助!
进度更新(感谢@WillisBlackburn):
struct iphdr *iph = ((struct iphdr *) full_packet);
fprintf(stdout, "IP{v=%u; ihl=%u; tos=%u; tot_len=%u; id=%u; ttl=%u; protocol=%u; "
,iph->version, iph->ihl*4, iph->tos, ntohs(iph->tot_len), ntohs(iph->id), iph->ttl, iph->protocol);
if (iph->protocol == 6){
struct tcphdr *tcp = ((struct tcphdr *) (full_packet + (iph->ihl << 2)));
uint8_t *p = (uint8_t *)tcp + 20;
uint8_t *end = (uint8_t *)tcp + tcp->doff * 4;
uint16_t mss = 0;
printf("\nThe offset is %d\n", tcp->doff);
printf("Let's check what's at location p: %u is supposed to be less than %d\n",(*(uint8_t *)tcp + 20), (uint8_t)end);
while (p < end) {
uint8_t kind = *p++;
if (kind == 0) {
printf("The kind is 0?\n");
break;
}
if (kind == 1) {
// No-op option with no length.
continue;
}
uint8_t size = *p++;
if (kind == 2) {
mss = ntohs(*(uint16_t *)p);
printf("The MSS value is: %d\n", mss);
}
p += (size - 2);
}
fprintf(stdout, "TCP{sport=%u; dport=%u; seq=%u; ack_seq=%u; flags=u%ua%up%ur%us%uf%u; window=%u; urg=%u}\n",
ntohs(tcp->source), ntohs(tcp->dest), ntohl(tcp->seq), ntohl(tcp->ack_seq)
,tcp->urg, tcp->ack, tcp->psh, tcp->rst, tcp->syn, tcp->fin, ntohs(tcp->window), tcp->urg_ptr);
}
更多进展:
找到一些很酷的读取TCP选项的实现;但是,我在我的代码中实现它并不十分确定。人们的帮助吗?这是我发现的:
它似乎比威利斯·布莱克本更复杂,并且可能会因为太大而解决这个问题? (200+带有一些数据包,而不是&#34; 2&#34;我们期望用MSS(+ TCP数据包中的其他选项)。
帮助表示赞赏!!!
如果您想谈论它,我将在#adamc频道的chat.freenode.net(niven.freenode.net)中!
最新更新:
所以,我的基础是MTCP,但这里是代码:(添加了用户测试):
const unsigned char *ptr;
const struct tcphdr *th = ((struct tcphdr *) (full_packet + (iph->ihl << 2)));
int length = (th->doff * 4) - sizeof(struct tcphdr);
ptr = (const unsigned char *)(th + 1);
while(length > 0){
printf("Got in the while loop\n");
int opcode = *ptr++;
int opsize;
switch(opcode) {
case 0:
printf("Got the initial val (EOL)\n");
return;
case 1:
printf("Got the NOP val as well!\n");
length--;
continue;
default:
printf("Entered default.\n");
opsize = *ptr++;
printf("Does stuff after setting the OPSize.\n");
if(opsize < 2) {
printf("OPSize = %d < 2;Length = %d\n", opsize, length);
return;
}
if(opsize > length) {
printf("OPSize = %d > Length = %d\n", opsize, length);
return;
}
switch(opcode) {
printf("Switching the OPCode\n");
case 2: //TCP MSS
if(opsize == 4 && th->syn) {
printf("MSS: %d\n", ptr);
}
case 3: //TCP Window
if(opsize==3 && th->syn) {
uint8_t wscale = *(uint8_t *)ptr;
if(wscale>14) {
printf("Illgal wscale value: %d\n", wscale);
}
printf("WSCALE: %d\n", *(uint8_t*)ptr);
}
break;
case 8: //Timestamp
if(opsize==10) {
printf("Timestamp is present!!!\n");
}
break;
case 4: //TCP SACK
if((opsize >= (2+8)) && !((opsize-2)%8)) {
printf("SACK val: %d\n", ((ptr-2)- (unsigned char *)th));
}
default:
printf("Entered default of switching OPCode\n");
return;
}
ptr += opsize-2;
length -= opsize;
}
}
所以我现在就以下问题: 当我提出请求时,它给了我以下内容:
IP{v=4; ihl=20; tos=0; tot_len=64; id=48952; ttl=61; protocol=6; Got in the while loop
Entered default.
Does stuff after setting the OPSize.
OPSize = 127 > Length = 12
所以基本上,它进入了while循环,输入了默认值(在opsizes之间切换)和所有内容;但是,OPSize是127(大于长度),所以我相信我在获取尺寸方面做错了。任何帮助将不胜感激!
答案 0 :(得分:2)
有两种可能的答案:如何获取TCP连接的MSS(最大段大小)以及如何解析TCP标头。
如果您只想知道连接的MSS是什么,那么您可以在打开的套接字上使用getsockopt
函数。传递文件描述符,IPPROTO_TCP作为级别,TCP_INFO作为选项,struct tcp_info
(来自tcp.h)将保存输出的地址,以及sizeof (struct tcp_info)
。内核将填写struct tcp_info
字段,您可以从tcpi_snd_mss
或tcpi_rcv_mss
获取MSS。
如果您确实想要解析TCP标头本身,那么您必须了解标头的布局。您使用的struct tcphdr
不包含struct tcphdr
字段后面的选项。每个选项字段都是标识选项类型的单个字节,可选地后跟第二个字节,指定选项的大小(包括种类和大小字节),然后是其他数据。
可能没有任何选择。您必须首先查看TCP标头(doff
)的数据偏移字段。它是32位字。由struct tcphdr
定义的标准头的大小为20个字节,因此只有doff
大于5(4个字节= 20个字节)时才能出现选项。
假设有选项,您可以像这样阅读它们。请注意,MSS的选项类型为2,选项类型0表示选项列表的结尾,但仅当选项列表的末尾不符合doff
的数据开头时。选项类型0和1(无操作)是单个字节。其他选项类型的大小字节跟在种类之后,并指定选项字段的大小(包括种类和大小字段)。
uint8_t *p = (uint8_t *)tcp + 20; // or sizeof (struct tcphdr)
uint8_t *end = (uint8_t *)tcp + tcp->doff * 4;
uint16_t mss = 0;
while (p < end) {
uint8_t kind = *p++;
if (kind == 0) {
break;
}
if (kind == 1) {
// No-op option with no length.
continue;
}
uint8_t size = *p++;
if (kind == 2) {
mss = ntohs(*(uint16_t *)p);
}
p += (size - 2);
}
我没有测试过这个,但它应该非常接近。
我找不到任何确认只有TCP选项0和1不包含大小字节的文档。 TCP的规范是RFC 793,它(在撰写本文时)已有35年历史,仅提及选项类型0,1和2.它表明大小字节是否存在取决于选项类型。但这意味着,为了正确解析标题,您的程序必须知道all the possible options it might encounter。例如,如果标头的选项段包含字节16,2,4,1和0,那么这是指类型16的选项,后跟大小字节2,后跟选项类型4(因为大小) 2表示该选项仅包括种类和大小)?或者它是指类型16的选项,没有大小字节,后面是类型2(MSS)的选项,后跟大小字节4?除非您知道选项类型16“Skeeter”是否应跟随大小字节,否则您无法知道。