原始套接字-自定义IP首部和TCP首部

Posted shuoed

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原始套接字-自定义IP首部和TCP首部相关的知识,希望对你有一定的参考价值。

 

  1 /* =====================================================================================
  2 *
  3 *       Filename:    raw.c
  4 *    Description:    使用原始套接字发送TCP协议,并外带自己的数据。
  5 *
  6 * ====================================================================================*/
  7 #include <stdio.h>
  8 #include <stdlib.h>
  9 #include <string.h>
 10 #include <sys/socket.h>
 11 #include <netinet/in.h>
 12 #include <netinet/ip.h>
 13 #include <netinet/tcp.h>
 14 #include <arpa/inet.h>
 15 #define DATA "hello"
 16 #define PACKET_SIZE sizeof(struct iphdr) + sizeof(struct tcphdr) + sizeof(DATA)
 17 
 18 /*---------------------------------------------------------
 19  Function Name : check_sum()
 20    Descrypthon : 校验和计算,摘自UNP源码
 21 ------------------------------------------------------------*/
 22 unsigned short check_sum(unsigned short *addr, int len)
 23 {
 24     int nleft = len;
 25     int sum = 0;
 26     unsigned short *w = addr;
 27     short answer = 0;
 28     while (nleft > 1)
 29     {
 30         sum += *w++;
 31         nleft -=2;
 32     }
 33     if (nleft == 1)
 34     {
 35         *(unsigned char *)(&answer) = *(unsigned char *)w;
 36         sum += answer;
 37     }
 38     sum = (sum >> 16) + (sum & 0xffff);
 39     sum += (sum >> 16);
 40     answer = ~sum;
 41     return answer;
 42 }
 43 
 44 /*---------------------------------------------------------
 45  Function Name : init_socket()
 46    Descrypthon : 初始化socket,使用原始套接字
 47    parameter   : P1 一个待初始化的原始套接字,P2 待初始化的目标地址结构,P3 目标地址,P4 目标端口
 48    return      : 返回一个原始套接字,在函数体内将目标地址结构进行初始
 49 ------------------------------------------------------------*/
 50 int init_socket(int sockfd, struct sockaddr_in *target,const char *dst_addr, const char *dst_port)
 51 {
 52     const int flag = 1;
 53     //目标协议簇
 54     target->sin_family = AF_INET;
 55     //目标端口
 56     target->sin_port = htons(atoi(dst_port));
 57 
 58     //将dst_addr中的ASCII-IP地址更新到target->sin_addr结构中
 59     if (inet_aton(dst_addr, &target->sin_addr) == 0)
 60     {
 61         perror("inet_aton fail\n");
 62         exit(-1);
 63     }
 64     //初始化原始套接字
 65     if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
 66     {
 67         perror("error");
 68         exit(-1);
 69     }
 70     //设置套接字×××
 71     if (setsockopt(sockfd,IPPROTO_IP, IP_HDRINCL, &flag, sizeof(flag)) < 0)
 72     {
 73         perror("setsockopt fail \n");
 74         exit(-1);
 75     }
 76     return sockfd;
 77 }
 78 
 79 /*---------------------------------------------------------------
 80  Function Name : buile_iphdr()
 81    Descrypthon : 构建IP头部数据, 源地址使用伪随机地址
 82 -----------------------------------------------------------------*/
 83 void buile_iphdr(struct sockaddr_in *target, char *buffer)
 84 {
 85     struct iphdr *ip = (struct iphdr *)(buffer);
 86     ip->version = 4;//版本
 87     ip->ihl = 5;//首部长度 5*4 = 20
 88     ip->tos = 0;//8位服务类型
 89     ip->tot_len = htons(PACKET_SIZE);//16位总长度
 90     ip->id = 0;//16位标识符
 91     ip->frag_off = 0;//3位标志
 92     ip->ttl = 255;//生存时间
 93     ip->protocol = IPPROTO_TCP;//协议
 94     ip->check = check_sum((unsigned short *)ip, sizeof(struct iphdr) + sizeof(DATA));//16位首部校验和
 95     ip->saddr = random();//源ip地址
 96     ip->daddr = target->sin_addr.s_addr;//目标ip地址
 97 }
 98 
 99 /*---------------------------------------------------------------
100  Function Name : buile_tcphdr()
101    Descrypthon : 构建TCP头部信息,并加入一些自己的数据,然后进行
102                  校验计算。
103 -----------------------------------------------------------------*/
104 void buile_tcphdr(struct sockaddr_in *target, const char *src_port, char *buffer)
105 {
106     struct tcphdr *tcp = (struct tcphdr *)(buffer);
107     tcp->source = htons(atoi(src_port));//16位源端口号
108     tcp->dest = target->sin_port;//16位目的端口号
109     tcp->seq = random();//32位序号
110     tcp->doff = 5;//
111     tcp->syn = 1;//同步序号
112     buffer += sizeof(struct tcphdr);
113     tcp->check = check_sum((unsigned short *)tcp, sizeof(struct tcphdr) + sizeof(DATA));//16位检验和
114     memcpy(buffer, DATA, sizeof(DATA));//将DATA中的数据拷贝sizeof(DATA)字节到buffer所指的地址中
115 }
116 int main(int argc, const char *argv[])
117 {
118     char *buffer;
119     char *buffer_head = NULL;
120     int sockfd = 0;
121     struct sockaddr_in *target;
122     if (argc != 4)
123     {
124         printf("usage: destination addresss, destination port, source port \n");
125         exit(-1);
126     }
127     const char *dst_addr = argv[1];
128     const char *dst_port = argv[2];
129     const char *src_port = argv[3];
130 
131     target = calloc(sizeof(struct sockaddr_in),1);
132     //calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。
133     buffer = calloc(PACKET_SIZE, 1);
134     buffer_head = buffer;
135 
136     //初始化套接字
137     sockfd = init_socket(sockfd, target, dst_addr, dst_port);
138     //创建IP首部
139     buile_iphdr(target, buffer);
140     buffer += sizeof(struct iphdr);//指针下移
141     //创建TCP首部
142     buile_tcphdr(target, src_port, buffer);
143     //发送
144     sendto(sockfd, buffer_head, PACKET_SIZE, 0,(struct sockaddr *)target, sizeof(struct sockaddr_in));
145 
146     //下两行是对calloc申请的释放
147     free(buffer_head);
148     free(target);
149     return 0;
150 }

 

以上是关于原始套接字-自定义IP首部和TCP首部的主要内容,如果未能解决你的问题,请参考以下文章

ip数据报格式

确认号啥时候有意义

TCP/IP

IP校验和

考研计算机 | 计算机网络-TCP协议与IP协议格式联结性问题

IP分组