BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / soft-design / #41694同步于 2011/12/23
该镜像源已超过 30 天没有更新,可能在源站已被删除。
SoftDesign机器人发帖

TCP raw socket chksum 死活不对,求助!

leoest
2011/12/23镜像同步8 回复
看网上有说tcp的chksum = 0的话 kernel 会自动补全,但是我这里一直是0, 如果加上tcp chksum语句的话,校验值却总是错误的。google了好多文档都没有解决。另外 IP 的那个 chksum 倒是 计算不计算都没什么区别,tcpdump显示都一样,很奇怪的说。 我这里的环境是x86_64 Linux。 tcpdump: 127.0.0.1.22345 > 127.0.0.1.22346: Flags [S], cksum 0x0000 (incorrect -> 0x109c), seq 1732610923, win 0, length 0 加上tcp chksum 127.0.0.1.22345 > 127.0.0.1.22346: Flags [S], cksum 0x0eb9 (incorrect -> 0x109c), seq 1732610923, win 0, length 0 代码: #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/ip.h> #include <netinet/tcp.h> #define MAX_PACKET_SIZE 4096 /* function for header checksums */ unsigned short ip_chksum(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 (unsigned short)(~sum); } void ip_header_init(struct iphdr *iph) { iph->version = 4; iph->ihl = 5; iph->tos = 0; iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); iph->id = htonl(54321); /* no need to set this value if we set DF */ iph->frag_off = 0; iph->ttl = MAXTTL; /* MAXTTL = 255 */ iph->protocol = 6; /* upper layer protocol, TCP */ iph->check = 0; /* Initial IP */ iph->saddr = inet_addr("127.0.0.1"); iph->daddr = inet_addr("127.0.0.1"); } void tcp_header_init(struct tcphdr *tcph) { tcph->source = htons(22345); // tcph->dest = htons(22346); tcph->seq = random(); tcph->ack_seq = 0; tcph->res2 = 0; tcph->doff = 5; tcph->syn = 1; tcph->window = htonl(65535); tcph->check = 0; tcph->urg_ptr = 0; } int main(int argc, char *argv[]) { int sockfd, on =1; unsigned int dport; char data[MAX_PACKET_SIZE]; struct iphdr *iph = (struct iphdr *)data; struct tcphdr *tcph = (struct tcphdr *)(data + sizeof(struct iphdr)); struct sockaddr_in dst; if(argc != 3) { fprintf(stderr, "Invalid parameters!\n"); fprintf(stdout, "Usage: %s <target> <port>\n", argv[0]); exit(1); } if ( (sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { perror("Socket raw error "); exit(1); } dport = atoi(argv[2]); dst.sin_family = AF_INET; dst.sin_port = htons(dport); dst.sin_addr.s_addr = inet_addr(argv[1]); /* init ip and tcp headers */ bzero(data, sizeof(data)); ip_header_init(iph); tcp_header_init(tcph); iph->daddr = dst.sin_addr.s_addr; tcph->dest = htons(dport); iph->check = chksum((unsigned short *)data, iph->tot_len); // tcph->check = chksum((unsigned short *)tcph, sizeof(struct tcphdr)); if ( setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) { perror("setsockopt IP_HDRINCL error"); exit(1); } if (sendto(sockfd, data, iph->tot_len, 0, (struct sockaddr *)&dst, \ sizeof(dst)) < 0) { perror("send to error"); exit(1); } return 0; }
订阅后,新回复会通过你的通知中心匿名送达。
8 条回复
leoest机器人#1 · 2011/12/24
求助求助,有大牛可以给找找原因吗?
purevirtual机器人#2 · 2011/12/24
没太研究过tcp udp的checksum倒是设为0 是不检查 tcp的checksum我记得又相应的函数啊 就算找不到,那个算法随便网上一搜就有,你自己手动加上试试 【 在 leoest (酹江月) 的大作中提到: 】 : 看网上有说tcp的chksum = 0的话 kernel 会自动补全,但是我这里一直是0, 如果加上tcp chksum语句的话,校验值却总是错误的。google了好多文档都没有解决。另外 IP 的那个 chksum 倒是 计算不计算都没什么区别,tcpdump显示都一样,很奇怪的说。 我这里的环境是x86_64 L : tcpdump: : 127.0.0.1.22345 > 127.0.0.1.22346: Flags [S], cksum 0x0000 (incorrect -> 0x109c), seq 1732610923, win 0, length 0 : ...................
leoest机器人#3 · 2011/12/24
【 在 purevirtual 的大作中提到: 】 : 没太研究过tcp : udp的checksum倒是设为0 是不检查 : tcp的checksum我记得又相应的函数啊 就算找不到,那个算法随便网上一搜就有,你自己手动加上试试 : ................... 网上找了好几种算法了,都不行,而且有的说需要校验,有的说设置为0让内核校验,但是没一个成功的。不知道是哪里出的问题。
purevirtual机器人#4 · 2011/12/24
只能用最笨的方法了 你有那本andrew的经典教材 计算机网络吗?那里面的checksum算法绝对是正确的 你就按照那个手敲就去吧 我这还要赶论文和准备考试 要是平时就帮你找找了 【 在 leoest (酹江月) 的大作中提到: 】 : 网上找了好几种算法了,都不行,而且有的说需要校验,有的说设置为0让内核校验,但是没一个成功的。不知道是哪里出的问题。
leoest机器人#5 · 2011/12/25
【 在 purevirtual 的大作中提到: 】 : 只能用最笨的方法了 你有那本andrew的经典教材 计算机网络吗?那里面的checksum算法绝对是正确的 你就按照那个手敲就去吧 : 我这还要赶论文和准备考试 要是平时就帮你找找了 : 【 在 leoest (酹江月) 的大作中提到: 】 : ................... 下载了你说的这本书,没找到……但是我用过Richard Stevens UNIX网络编程 的checksum算法,还是有问题……不知道是不是我的代码也有问题
purevirtual机器人#6 · 2011/12/25
不知道了 按理说他库里提供的就可以用 lz解决了别忘了更新一下 【 在 leoest (酹江月) 的大作中提到: 】 : 下载了你说的这本书,没找到……但是我用过Richard Stevens UNIX网络编程 的checksum算法,还是有问题……不知道是不是我的代码也有问题
leoest机器人#7 · 2011/12/25
【 在 purevirtual 的大作中提到: 】 : 不知道了 按理说他库里提供的就可以用 : lz解决了别忘了更新一下 : 【 在 leoest (酹江月) 的大作中提到: 】 : ................... 终于解决了,原来由于TCP首部中不包含源地址与目标地址等信息,为了保证TCP校验的有效性,在进行TCP校验和的计算时,需要增加一个TCP伪首部的校验和,定义如下 struct pseudo_header { unsigned int source_address; unsigned int dest_address; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; }; 然后将这个伪首部填充并计算校验和放入TCP校验和那里就搞定啦,哈哈! TCPDUMP抓包 23:46:48.946735 IP 127.0.0.1.italk > 127.0.0.1.22345: Flags [S], seq 0, win 4096, length 0 23:46:48.946766 IP 127.0.0.1.22345 > 127.0.0.1.italk: Flags [S.], seq 157357738, ack 1, win 32792, options [mss 16396], length 0 23:46:48.946783 IP 127.0.0.1.italk > 127.0.0.1.22345: Flags [R], seq 1, win 0, length 0 最后client端会发出reset,为什么出现这种情况大家可以自己google一下,呵呵。 最后附上改好后的程序 #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/ip.h> #include <netinet/tcp.h> #define MAX_PACKET_SIZE 4096 //needed for checksum calculation struct pseudo_header { unsigned int saddr; unsigned int daddr; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; }; /* function for header checksums */ unsigned short cal_chksum(unsigned short *addr,int len) { int nleft=len; int sum=0; unsigned short *w=addr; unsigned short answer=0; while(nleft>1) { sum+=*w++; nleft-=2; } if( nleft==1) { *(unsigned char *)(&answer)=*(unsigned char *)w; sum+=answer; } sum=(sum>>16)+(sum&0xffff); sum+=(sum>>16); answer=~sum; return answer; } void ip_header_init(struct iphdr *iph) { iph->version = 4; iph->ihl = 5; iph->tos = 0; iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); iph->id = htons(54321); /* no need to set this value if we set DF */ iph->frag_off = 0; iph->ttl = MAXTTL; /* MAXTTL = 255 */ iph->protocol = 6; /* upper layer protocol, TCP */ iph->check = 0; /* Initial IP */ iph->saddr = inet_addr("127.0.0.1"); iph->daddr = inet_addr("127.0.0.1"); } void tcp_header_init(struct tcphdr *tcph) { tcph->source = htons(12345); tcph->dest = htons(22345); tcph->seq = 0 ; tcph->ack_seq = 0; tcph->res2 = 0; tcph->doff = 5; tcph->fin = 0; tcph->syn = 1; tcph->rst = 0; tcph->psh = 0; tcph->ack = 0; tcph->urg = 0; tcph->window = htons(4096); tcph->check = 0; tcph->urg_ptr = 0; } int main(int argc, char *argv[]) { int sockfd, on =1; unsigned int dport; char data[MAX_PACKET_SIZE]; struct iphdr *iph = (struct iphdr *)data; struct tcphdr *tcph = (struct tcphdr *)(data + sizeof(struct iphdr)); struct sockaddr_in dst; struct pseudo_header psh; if(argc != 3) { fprintf(stderr, "Invalid parameters!\n"); fprintf(stdout, "Usage: %s <target> <port>\n", argv[0]); exit(1); } if ( (sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { perror("Socket raw error "); exit(1); } dport = atoi(argv[2]); dst.sin_family = AF_INET; dst.sin_port = htons(dport); dst.sin_addr.s_addr = inet_addr(argv[1]); /* init ip and tcp headers */ bzero(data, sizeof(data)); ip_header_init(iph); tcp_header_init(tcph); iph->daddr = dst.sin_addr.s_addr; tcph->dest = htons(dport); /* Don't need set ip chksum , kernel will fill in the correct checksum*/ // iph->check = csum((unsigned short *)data, iph->tot_len); psh.saddr = iph->saddr; psh.daddr = iph->daddr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; /* tcp_len shoud use network bytes , can't directly use sizeof(struct tcphdr) */ psh.tcp_length = htons(sizeof(struct tcphdr)); memcpy(&psh.tcp, tcph, sizeof(struct tcphdr)); tcph->check = cal_chksum((unsigned short *)&psh, sizeof(struct pseudo_header)); if ( setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) { perror("setsockopt IP_HDRINCL error"); exit(1); } if (sendto(sockfd, data, iph->tot_len, 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) { perror("send to error"); exit(1); } return 0; } 参考链接: http://hi.baidu.com/wwwanq/blog/item/c47426253b3e5c35c995590c.html http://www.binarytides.com/blog/syn-flood-dos-attack/ 下一步目标:实现client ack应答,模拟出tcp三次握手。
zxsword机器人#8 · 2011/12/27
此楼不错,楼上都是大牛。