linux原始套接字raw获取ip包,Linux网络编程:原始套接字 SOCK_RAW, IPV6 rawsocket

比较新的内核才支持

socket(fd, SOCK_RAW, IPPROTO_UDP); // 指定 TCP/UDP/ICMPint val = 1;ret = setsockopt(test->state.sockfd, IPPROTO_IPV6, IPV6_HDRINCL, &val, sizeof(val)); // 比较新的内核才支持remote.sin6_port = 0; // 必须设置成0sendto (socketFd, buffer, len, 0, (struct sockaddr *) &remote, sizeof(remote));

一、修改iphdr+tcphdr

对于TCP或UDP的程序开发,焦点在Data字段,我们没法直接对TCP或UDP头部字段进行赤裸裸的修改,当然还有IP头。换句话说,我们对它们头部操作的空间非常受限,只能使用它们已经开放给我们的诸如源、目的IP,源、目的端口等等。

原始套接字的创建方法:

socket(AF_INET, SOCK_RAW, protocol);

重点在protocol字段,这里就不能简单的将其值为0了。在头文件netinet/in.h中定义了系统中该字段目前能取的值,注意:有些系统中不一定实现了netinet/in.h中的所有协议。源代码的linux/in.h中和netinet/in.h中的内容一样。我们常见的有IPPROTO_TCP,IPPROTO_UDP和IPPROTO_ICMP。

用这种方式我就可以得到原始的IP包了,然后就可以自定义IP所承载的具体协议类型,如TCP,UDP或ICMP,并手动对每种承载在IP协议之上的报文进行填充。

先简单复习一下TCP报文的格式

6c5084752c87addfb4ea74494d8908a3.png

ee2ee27bc7a9e6f27d865d6b2730db67.png

原始套接字还提供了一个非常有用的参数IP_HDRINCL:

1、当开启该参数时:我们可以从IP报文首部第一个字节开始依次构造整个IP报文的所有选项,但是IP报文头部中的标识字段(设置为0时)和IP首部校验和字段总是由内核自己维护的,不需要我们关心。

2、如果不开启该参数:我们所构造的报文是从IP首部之后的第一个字节开始,IP首部由内核自己维护,首部中的协议字段被设置成调用socket()函数时我们所传递给它的第三个参数。

开启IP_HDRINCL特性的模板代码一般为:

const int on =1;if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {printf("setsockopt error!\n");}

所以,我们还得复习一下IP报文的首部格式:

0b83036e3a873c5f888685581c67225d.png

同样,我们重点关注IP首部中的着色部分区段的填充情况。

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include unsigned csum_tcpudp_nofold(unsigned saddr, unsigned daddr,unsigned len, unsigned proto, unsigned sum){unsigned long long s = (unsigned)sum;s += (unsigned)saddr;s += (unsigned)daddr;s += (proto + len) << 8;s += (s >> 32);return (unsigned)s;}unsigned short check_sum(unsigned short *addr, int len, unsigned sum){int nleft = len;unsigned short *w = addr;unsigned short ret = 0;while (nleft > 1) {sum += *w++;nleft -= 2;}if (nleft == 1) {*(unsigned char *)(&ret) = *(unsigned char *)w;sum += ret;}sum = (sum>>16) + (sum&0xffff);sum += (sum>>16);ret = ~sum;return ret;}//在该函数中构造整个IP报文,最后调用sendto函数将报文发送出去void attack(int skfd, struct sockaddr_in *target, unsigned short srcport){char buf[256] = {0};struct ip *ip;struct tcphdr *tcp;int ip_len;int op_len = 12;//在我们TCP的报文中Data没有字段,所以整个IP报文的长度ip_len = sizeof(struct ip) + sizeof(struct tcphdr) + op_len;//开始填充IP首部ip=(struct ip*)buf;ip->ip_v = IPVERSION;ip->ip_hl = sizeof(struct ip)>>2;ip->ip_tos = 0;ip->ip_len = htons(ip_len);ip->ip_id = 0;ip->ip_off = 0;ip->ip_ttl = MAXTTL;ip->ip_p = IPPROTO_TCP;ip->ip_sum

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值