原始套接字--结构体总结

2024-11-03  本文已影响0人  锈色的栅栏

以太网头部 (ethernet-- 以太网)

struct ether_header     #include<net/ethernet.h>

struct ether_header
{
         u_int8_t    ether_dhost[ETH_ALEN];  //目的MAC地址
         u_int8_t    ether_shost[ETH_ALEN];  //源MAC地址
         u_int16_t  ether_type;                        //帧类型
};

IP报文头

 struct iphdr           #include <netinet/ip.h>
 struct iphdr
{
        #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ihl:4;                                      // 首部长度
        unsigned int version:4;                              // 版本
        #elif __BYTE_ORDER == __BIG_ENDIAN    
        unsigned int version:4;                              //版本
        unsigned int ihl:4;                                      //首部长度
        #else
        # error "Please fix <bits/endian.h>"
        #endif
        u_int8_t tos;                                                // 服务类型
        u_int16_t tot_len;                                        // 总长度
        u_int16_t id;                                                // 表识
        u_int16_t frag_off;                                      // 标志、片偏移
        u_int8_t ttl;                                                  // 生存时间
        u_int8_t protocol;                                        // 协议
        u_int16_t check;                                          // 首部校验和
        u_int32_t saddr;                                          // 源地址
        u_int32_t daddr;                                          // 目的地址
      /*The options start here. */
};

用于生成校验位

unsigned short checksum(unsigned short *buf, int len){
        int nword = len /2;
        unsigned long sum;

         if(len %2==1)
                   nword++;

        for(sum =0; nword >0; nword--)
        {   
                sum += *buf;   
                buf++;
        }
        sum = (sum >>16) + (sum &0xffff);
        sum += (sum >>16); 
        return~sum;

UDP

1、源端口号:发送方端口号。
2、目的端口号:接收方端口号。
3、长度:UDP用户数据报的长度,最小值是8(仅有首部)。
4、校验和:检测UDP用户数据报在传输中是否有错,有错就丢弃。
5、结构体

 struct udphdr           #include<netinet/udp.h>

  struct udphdr {
           u_int16_t source;        // 源端口号
           u_int16_t dest;            // 目的端口号
           u_int16_t len;              // 长度
           u_int16_t check;          // 校验和
  };

UDP伪头部

IP、ICMP、UDP和TCP报文头都有检验和字段,大小都是16bit。

(1)IP校验和:IP首部。
(2)ICMP校验和:ICMP首部+ICMP数据
(3)UDP、TCP校验和:12个字节伪首部(源IP地址、目的IP地址、协议、TCP/UDP包长)+首部+数据

//自定义结构体,表示UDP伪首部的信息

struct udp_fakehdr{
        u_int32_t sip; //源ip
        u_int32_t dip; //目的ip
        u_int8_t flags; //0
        u_int8_t prot; //协议类型-17
        u_int16_t len; //UDP报文长度
};

ARP

struct  arphdr #include <net/if_arp.h>

 struct arphdr{
            unsigned  short  int  ar_hrd;                        // 硬件类型
            unsigned  short  int  ar_pro;                        //  协议类型
            unsigned  char  ar_hln;                                // 硬件地址长度
            unsigned  char  ar_pln;                                // 协议地址长度
            unsigned  short  int  ar_op;                          // ARP命令

   # if  0
            /*  Ethernet  looks  like  this  :  This  bit  is  variable  sized  however  . . .  */
            unsigned  char  __ar_sha[ETH_ALEN];      // 发送端以太网地址
            unsigned  char  __ar_sip[4];                        // 发送端IP地址
            unsigned  char  __ar_tha[ETH_ALEN];      // 目的以太网地址
            unsigned  char  __ar_tip[4];                        // 目的IP地址
 # endif
};

由于上面条件编译的条件始终为0(假)   所以我们需要自定义ARP协议报文结构体--将条件该为1

struct arp_header  {   
            unsigned short int ar_hrd; //硬件地址类型   
            unsigned short int ar_pro; //协议地址类型能够   
            unsigned char ar_hln; //硬件地址长度   
            unsigned char ar_pln; //协议地址长度   
            unsigned short int ar_op; //ARP操作码   
            unsigned char __ar_sha[ETH_ALEN]; //源mac地址   
            unsigned char __ar_sip[4]; //源ip   
            unsigned char __ar_tha[ETH_ALEN]; //目的mac   
            unsigned char __ar_tip[4]; //目的ip 
 };

TCP:

struct tcphdr       #include <netinet/tcp.h>

struct tcphdr  {
            u_int16_t source;        // 源端口号
            u_int16_t dest;            // 目的端口号
            u_int32_t seq;              // 序列号
            u_int32_t ack_seq;      // 确认序列
 #  if __BYTE_ORDER == __LITTLE_ENDIAN
            u_int16_t res1:4;        //
            u_int16_t doff:4;          // 保留:4
            u_int16_t fin:1;            // 终止FIN
            u_int16_t syn:1;          // 同步SYN
            u_int16_t rst:1;          // 复位RST
            u_int16_t psh:1;        // 推送PSH
            u_int16_t ack:1;        // 确认ACK
            u_int16_t urg:1;        // 紧急URG
            u_int16_t res2:2;      // 保留:2
#  elif __BYTE_ORDER == __BIG_ENDIAN
            u_int16_t doff:4;        // 首部长度
            u_int16_t res1:4;      // 保留:4
            u_int16_t res2:2;      // 保留:2
            u_int16_t urg:1;        // 紧急URG
            u_int16_t ack:1;        // 确认ACK
            u_int16_t psh:1;        // 推送PSH
            u_int16_t rst:1;          // 复位RST
            u_int16_t syn:1;        // 同步SYN
            u_int16_t fin:1;          // 终止FIN
  #  else
        #  error " Adjust your <bits/endian.h> defines"
  #  endif   
            u_int16_t window;    // 窗口
            u_int16_t check;      //校验和
            u_int16_t urg_ptr;    //紧急指针
}; 

示例代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
typedef struct {
        unsigned int saddr;
        unsigned int daddr;
        unsigned char flags;
        unsigned char type;
        unsigned short len;
}WEI;

void sys_err(const char *str){
        perror(str);
        exit(1);
}

unsigned short checksum(unsigned short *buf, int len){   
        int nword = len / 2; 
        unsigned long sum;   
        if (len % 2 == 1)       
                nword++;   
        for (sum = 0; nword > 0; nword--)   
        {       
                sum += *buf;       
                buf++;   
         }   
        sum = (sum >> 16) + (sum & 0xffff);   
        sum += (sum >> 16);   
        return ~sum;
 } 

int my_sendto(int sockfd,unsigned char *msg, int len, char *name){
        struct ifreq ethreq;
        strncpy(ethreq.ifr_name,name,IFNAMSIZ);
        if(-1 == ioctl(sockfd,SIOCGIFINDEX,&ethreq))
                 sys_err("ioctl error");

        struct sockaddr_ll sll;
        bzero(&sll,sizeof(sll));
        sll.sll_ifindex = ethreq.ifr_ifindex;
        int l = sendto(sockfd,msg,len,0,(struct sockaddr *)&sll,sizeof(sll));
        return l;
}
int main(int argc,char *argv[]){
        int sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));//创建原始套接字
        unsigned char buf[1500] = "";
        unsigned char data[128] = "";
        fgets(data,sizeof(data),stdin);
        data[strlen(data) - 1] = 0;
        int data_len = strlen(data) + strlen(data)/2;
        //mac
        unsigned char src_mac[6] = {0x00,0x0c,0x29,0x76,0x05,0xa5};
        unsigned char dst_mac[6] = {0x7c,0x67,0xA2,0x94,0x1C,0xDB};
        struct ether_header *eth_hd = (struct ether_header *)buf;
        memcpy(eth_hd->ether_dhost,dst_mac,6);
        memcpy(eth_hd->ether_shost,src_mac,6);
        eth_hd->ether_type = htons(0x0800);
        //ip
        struct iphdr *ip_hd = (struct iphdr *)(buf+14);
        ip_hd->version = 4;
        ip_hd->ihl = 5;
        ip_hd->tos = 0;
        ip_hd->tot_len = htons(20 + 8 + data_len);
        ip_hd->id = htons(0);
        ip_hd->frag_off = htons(0);
        ip_hd->ttl = 128;
        ip_hd->protocol = 17;
        ip_hd->check = 0;
        ip_hd->saddr = inet_addr("192.168.10.58");
        ip_hd->daddr = inet_addr("192.168.10.59");
        ip_hd->check = checksum((unsigned short *)ip_hd,20); 
         //udp
        struct udphdr *udp_hd = (struct udphdr *)(buf + 14 + 20);
        udp_hd->source = htons(8000);
        udp_hd->dest = htons(9999);
        udp_hd->len = htons(8 + data_len);
        udp_hd->check = 0;
        memcpy(buf+14+20+8,data,data_len);
        unsigned char wei_buf[512] = "";
        WEI *p = (WEI *)wei_buf;
        p->saddr = inet_addr("192.168.10.58");
        p->daddr = inet_addr("192.168.10.59");
        p->flags = 0; p->type = 17;
        p->len = htons(8+data_len);
        memcpy(wei_buf+12,udp_hd,8+data_len);
        udp_hd->check = checksum((unsigned short *)wei_buf,12+8+data_len);

        my_sendto(sockfd,buf,14+20+8+data_len,"ens37");
        close(sockfd);
        return 0;
}

上一篇 下一篇

猜你喜欢

热点阅读