`
memorymyann
  • 浏览: 271970 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

26.原始套接字

阅读更多

一个小程序:

//发送方

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>

struct mydata {
        char data[12];
};

int main(int argc, char ** argv) {
        struct mydata senddata;
        strcpy(senddata.data, "hello world");
        int sockfd;
        struct sockaddr_in addr;
        socklen_t addr_len = sizeof(addr);

        bzero(&addr, sizeof(struct sockaddr_in));
        addr.sin_family = AF_INET;
        inet_pton(AF_INET, argv[1], &addr.sin_addr);

        sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        char sendbuf[] = "hello world";
        int sendbuf_len = sendto(sockfd, (void *)&senddata, sizeof(struct mydata), 0, (struct sockaddr *)&addr, addr_len);
        printf("send len = %d\n", sendbuf_len);
        close(sockfd);
}

 

//接受方

#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>

void proc_v4(char *);
struct mydata {
        char data[12];
};

int main(int argc, char ** argv) {
        int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        char readbuf[100];
        int ipv = atoi(argv[1]);
        int len = read(sockfd, readbuf, ipv);
        printf("len = %d\n", len);
        proc_v4(readbuf);
        close(sockfd);
}

void proc_v4(char * package) {
        struct mydata * content;
        struct ip * ip = (struct ip *)package;
        struct in_addr from= ip->ip_src;
        printf("from %s: ", inet_ntoa(from));
        content = (struct mydata *)(package + sizeof(struct ip));
        printf("%s\n", content->data);
}

 

原本网上有一些用原始套接字的例子,但我找了很久只有2个版本,一个是用原始套接字发送ICMP包,另一个则是发送TCP包(带有攻击性质)。发送ICMP包,指定的服务类型为ECHO回显服务,而这是由内核提供的,也就是说我们必须要自己来写接受方,只要发送出去即可。TCP例子则是不停的向同一台机器发送请求连接的SYN包。缺点是:本来学习的主题是原始套接口,而这2个例子还要带上对TCP和ICMP的学习。(笔者太笨了,写了很久也没有让ICMP回显,可能是ICMP头部写的有问题,包被主机忽略了)。

 

我这里依然采用的是ICMP协议,但我没有自己写ICMP包头,只是简单把要传递的信息放入了ICMP包中,内核依然会将其送入接受的套接口中。

 

1.原始套接口创建

sockfd = socket(AF_INET, SOCK_RAW, 86);

第一个参数很熟悉了,表示IPV4,SOCK_RAW表示原始套接字,最后的86是我乱写。第3个参数可选值很多IPPROTO_ICMP或者IPPROTO_TCP。如果是IPPROTO_ICMP表示通过这个原始套接字发送的IP包中带的数据将会是ICMP包,依次理解IPPROTO_TCP则表示带为TCP包。而86则是内核没有支持的协议或者说内核不认识的协议。这些将会影响接受方内核对IP数据包的处理。

 

2.原始套接口输出

端口对原始套接口是没有意义的,一般使用sendto或者sendmsg发送,当然可以调用connect的原始套接字,则可以直接使用write。超过MTU的会被分片。

 

3.原始套接口的输入

回忆一下TCP和UDP,他们都是通过端口号和地址来找到接受进程。而原始套接口则不同。它遵循以下几个规则:

 a.如果发送方创建时候使用的socket(AF_INET,SOCK_RAW, IPPROTO_TCP),也就是从这个套接口出来的为TCP包,或者UDP包不会传递给任何原始套接口,他们将直接递交给TCP或者UDP协议处理。所以要想抓TCP或者UDP包,用原始套接口无法实现。

b.如果发送的是ICMP数据,除了回射,时间戳,地址掩码请求完全有内核处理,所有接受到的都将传递给某个原始套接口。(我理解是只要你创建了原始套接字,则这个套接字就会收到这个包的一个拷贝)。

c.如果是IGMP数据,所有IGMP分组将会传递某个原始套接口。

d.不能识别的协议字段,例如我上面的86,都将传递某个原始套接口。

e.被分片的包会重组再按照abcd处理。

f.ip包会进行版本,头部校验和,头部长度以及目的地址检查。检查不合格者会丢弃。

 

4.套接口选项IP_HDRINCL

上面程序比较简单,我没有打开这个选项,如果打开这个选项,则你写入的数据会从IP包头部开始,也就是说你需要写IP头部。

 

一个打开了IP_HDRINCL的原始套接字样例,接受方仍然可以采用原来的程序,这个程序修改了发送者的IP

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>

 

//计算IP头部校验和的算法

unsigned short 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 (unsigned short)(~sum);

}

 

struct mydata {

   char data[12];

};

 

int main(int argc, char ** argv) {

  char buf[400];

  struct ip * ip_head = (struct ip *)buf;

  struct mydata * senddata = (struct mydata *)(buf + sizeof(struct ip));

  int one = 1;

  const int * val = &one;

 

  memset(buf, 0, 400);

 

  int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

 

  bzero(&addr, sizeof(struct sockaddr_in));

  addr.sin_family = AF_INET;

  inet_pton(AF_INET, argv[1], &addr.sin_addr);

 

  //init ip head

  ip_head->ip_hl = 5; //头部长度

  ip_head->ip_v = 4;//ip版本号

  ip_head->ip_tos = 16;

  ip_head->ip_p = IPPROTO_ICMP; //服务类型

  inet_pton(AF_INET, argv[1], &ip_head->ip_dst); //指定目的IP地址

  inet_pton(AF_INET, "192.168.1.23", &ip_head->ip_src); //指定源IP地址,这里可以随便指定,不一定要是本机IP地址,当然如果不是本机地址,对方获得的就是错误地址,原始套接口没有确认包返回,所以不会有影响,但如果期望对方返回信息的话,就要填自己的IP地址。

 

  strcpy(senddata->data, "hello world");

  setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one));

 

  ip_head->ip_sum = csum((unsigned short *) buf, sizeof(struct ip) + sizeof(struct mydata));//计算校验和

  sendto(sockfd, buf, ip_head->ip_len, 0, (struct sockaddr *)&addr, sizeof(addr));

  close(sockfd);

  exit(0);

}

分享到:
评论

相关推荐

    原始套接字 原始套接字的创建

    ### 原始套接字的创建及其应用 #### 一、引言 在计算机网络领域,原始套接字(Raw Socket)是一种特殊类型的套接字,它允许应用程序直接访问并控制网络协议栈中的底层传输协议。通过使用原始套接字,开发人员可以...

    windows原始套接字抓包

    在Windows操作系统中,原始套接字(RAW Socket)是一种特殊类型的网络套接字,它允许程序员直接访问网络层,而不受传输层协议(如TCP或UDP)的限制。这种功能对于网络数据分析、网络安全检测和协议开发等场景非常...

    易语言原始套接字应用

    易语言原始套接字应用源码,原始套接字应用,显示信息,窗口消息处理,数据到达,异步通讯安装,异步通讯卸载,异步选择,异步处理,异步返回,UnHOOK,HOOKFunc,HOOKAPI,GetFunc,changefunc,CallFunc,数值_无符号_短整数,内存_...

    原始套接字

    原始套接字是一种特殊的网络套接字,允许用户直接处理IP协议数据包,而不经过标准的传输层协议如TCP或UDP封装。这种套接字在Linux操作系统中广泛应用于网络编程和管理,尤其适用于需要直接操纵网络层数据的应用程序...

    原始套接字 原始套接字

    原始套接字是一种低级别的网络通信机制,允许程序员直接操作网络协议栈的底层,从而能够执行高级网络编程任务。在大多数常规的网络编程中,我们使用的流式套接字(SOCK_STREAM)和数据报式套接字(SOCK_DGRAM)分别...

    基于winsock原始套接字的IP数据包的捕获与解析

    基于Winsock原始套接字的IP数据包捕获与解析 在计算机网络课程设计中,捕获和解析IP数据包是非常重要的一步。今天,我们将使用Windows Sockets(Winsock)的原始套接字来实现IP数据包的捕获和解析。本文将详细介绍...

    头歌ICMP Ping实现-Ping客户端创建原始套接字

    ICMP Ping实现-Ping客户端创建原始套接字ICMP Ping实现-Ping客户端创建原始套接字ICMP Ping实现-Ping客户端创建原始套接字ICMP Ping实现-Ping客户端创建原始套接字ICMP Ping实现-Ping客户端创建原始套接字ICMP Ping...

    利用原始套接字写的网络数据捕获

    标题中的“利用原始套接字写的网络数据捕获”指的是在网络编程中,通过使用操作系统提供的原始套接字(Raw Sockets)来实现网络数据的捕获和分析,而不是依赖于像WinPcap这样的第三方库。这种方法对于理解网络协议...

    基于原始套接字的网络嗅探器

    在将原始套接字设置完毕,使其能按预期目的工作时,就可以通过recv()函数从网卡接收数据了,接收到的原始数据包存放在缓存RecvBuf[]中,缓冲区长度BUFFER_SIZE定义为65535。然后就可以根据前面对IP数据段头、TCP数据...

    原始套接字测试程序

    原始套接字(Raw Sockets)是网络编程中一种特殊类型的套接字,它允许程序员直接操作IP层的数据包,而不仅仅是应用层的协议。在操作系统中,通常只有管理员权限的用户才能使用原始套接字,因为它们可以用来构建、...

    原始套接字数据包转发

    原始套接字(Raw Sockets)是网络编程中一种特殊类型的套接字,允许程序员直接操作网络协议的底层,而不依赖于操作系统提供的更高层次的服务。它们通常用于网络诊断、网络测试以及开发自定义的网络协议。在C#中,...

    原始套接字 socket

    尽做为想了解原始套接字或研究sniffer的朋友做示范操作 只要你具备相应的权限 只要在本机上运行本demo附带的exe 当你操作网络的时候就会把通过本机网卡的数据 给截获下来再gridlist中展示出来 目前只截获tcp udp ...

    原始套接字监听

    原始套接字监听是一种高级网络编程技术,它允许程序员直接操作网络层的数据包,而不仅仅是应用层的协议。在标题“原始套接字监听”中,我们关注的是使用原始套接字来监听和分析网络流量,这在网络安全、监控、故障...

    原始套接字发送完整UDP数据包(c语言实现)

    使用C语言实现原始套接字从数据链路层到应用层的操作,Linux系统

    原始套接字PPT

    原始套接字

    原始套接字发送iCMP自定义头部版本

    原始套接字(Raw Socket)是网络编程中的一个重要概念,它允许程序员直接操作TCP/IP协议栈,而不必受限于标准的TCP、UDP等高层协议。在这个主题中,“原始套接字发送iCMP自定义头部版本”指的是利用原始套接字来创建...

    Linux操作系统网络编程--原始套接字

    Linux操作系统中的网络编程涉及到各种类型的套接字,包括TCP套接字、UDP套接字以及原始套接字。原始套接字(SOCK_RAW)是一种特殊的套接字类型,允许程序员对网络协议栈进行更底层的控制。在这个场景下,我们将深入...

    yuanshitaojiezi.rar_原始套接字

    原始套接字(Raw Sockets)是网络编程中一种特殊类型的套接字,它允许程序员直接操作网络协议的底层细节,如IP头、TCP头或UDP头等。在大多数操作系统中,原始套接字通常与低级别的网络协议交互,如IPv4(IPPROTO_IP...

    原始套接字实现Ping命令和Tracert命令

    采用C++语言,基于原始套接字实现了Ping和Tracert命令。发送主机通过ping程序给目标主机发送ICMP的回声请求报文,并根据收到的ICMP回声应答报文来确定网络的连通性。Tracert(跟踪路由)是路由跟踪实用程序,用于...

    原始套接字 synflood攻击

    syn flood c的简易实现,编译即可

Global site tag (gtag.js) - Google Analytics