原始套接字-自定义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 }
时间: 2024-08-13 23:52:15

原始套接字-自定义IP首部和TCP首部的相关文章

关于原始套接字的两个小问题

1.原始套接字的协议是否可以设置为IPPRORO_TCP?UDP和TCP分组没有对应的套接字,此时会不会将其传递到原始套接口? 答: (1) 可以.对于socket()函数,在流式套接字编程中第二个参数是SOCK_STREAM,而对于数据报套接字编程,第二个参数是SOCK_DGRAM,在这两种情况下,第三个参数可以填0,这样系统会自动匹配相应的协议. 而原始套接字编程中,第二个参数是SOCK_RAW,在这种情况下,第三个参数必须指明相应的协议,协议类型的常用取值有 IPPROTO_IP.IPPR

原始套接字编程

原始套接字的特点 原始套接字(SOCK_RAW)可以用来自行组装IP数据包,然后将数据包发送到其他终端.也就是说原始套接字是基于IP数据包的编程(SOCK_PACKET是基于数据链路层的编程).另外,必须在管理员权限下才能使用原始套接字. 原始套接口提供了普通TCP和UDP socket不能提供的3个能力: 1.进程使用raw socket 可以读写ICMP.IGMP等分组.这个能力还使得使用ICMP或IGMP构造的应用程序能够完全作为用户进程处理,而不必往内核中添加额外代码. 2.大多数内核只

【转】网络编程原始套接字

转自:http://www.cnblogs.com/hnrainll/archive/2011/09/20/2182423.html SOCKET_STREAM 流式套接字      SOCKET_DGRAM        SOCKET_RAW 原始套接字    IPPROTO_IP IP协议    IPPROTO_ICMP INTERNET控制消息协议,配合原始套接字可以实现ping的功能    IPPROTO_IGMP INTERNET 网关服务协议,在多播中用到 在AF_INET地址族下,

ip欺骗(原始套接字系列九)

由于使用Raw Socket的时候,IP报头可完全由程序员自定义,所以我们可以任意地修改本地发送包的IP地址,使得接收方错误的认为IP报文是由欺骗地址发出的. 下面的程序演示了向某目标发送IP地址伪装的UDP报文的过程: void sendPesuoIpUDP(void){ WSADATA wsd; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { printf("WSAStartup() failed: %d ", GetLastErr

python使用原始套接字 解析原始ip头数据

使用底层套接字解码底层流量,是这次做的重点工作. 首先来捕获第一个包 # coding:utf-8import socket # 监听的主机IP host = "192.168.1.100" socket_protocol = socket.IPPROTO_ICMP sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) sniffer.bind((host, 0)) sniffer.setso

linux原始套接字(3)-构造IP_TCP发送与接收

一.概述                                                    tcp报文封装在ip报文中,创建tcp的原始套接字如下: 1 sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); 此时只能构造tcp报文,如果想进一步构造ip首部,那么就要开启sockfd的IP_HDRINCL选项: 1 int on = 1; 2 setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on

linux原始套接字(2)-icmp请求与接收

一.概述                                                    上一篇arp请求使用的是链路层的原始套接字.icmp封装在ip数据报里面,所以icmp请求可以直接使用网络层的原始套接字,即socket()第一个参数是PF_INET.如下: 1 sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); icmp报文不同的类型有不同的格式,我们以icmp回显请求和会显应答报文格式(即ping程序使用的报文类型)

原始套接字简介(原始套接字系列一)

大多数程序员所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的TCP服务应用: (2)数据报式套接字(SOCK_DGRAM):一种无连接的Socket,对应于无连接的UDP服务应用. 从用户的角度来看,SOCK_STREAM.SOCK_DGRAM这两类套接字似乎的确涵盖了TCP/IP应用的全部,因为基于TCP/IP的应用,从协议栈的层次上讲,在传输层的确只可能建立于TCP或UDP协议之上(图1),而SOCK_STRE

linux原始套接字(4)-构造IP_UDP

一.概述                                                    同上一篇tcp一样,udp也是封装在ip报文里面.创建UDP的原始套接字如下: 1 (sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP); 同样,如果要构造udp的ip首部,要开启IP_HDRINCL选项! udp首部格式: udp的不可靠性,比tcp报文简单很多.上面的16位UDP长度是UDP首部+普通数据的总长度,这点跟ip首部的16位总