mini Network-Analyzer
Part D:packet spoofing
实验结果:前8个包
文件结构
|-- Forge
|-- method.h
|-- method.c
|-- UDP_forge.h
|-- UDP_forge.c
|-- TCP_forge.h
|-- TCP_forge.c
|-- ARP_forge.h
|-- ARP_forge.c
|-- ICMP_forge.h
|-- ICMP_forge.c
|-- main
利用Raw
Socket可以实现发送用户自定义的数据包,在实现各种forgery之前,先定义一个工具文件method.h/method.c
,实现公共部分,定义的接口如下
void get_eth_index(int sock_raw);
void get_mac(int sock_raw, uint16_t protocol, int *total_len);
void str2ip(char *src, unsigned char *dst);
unsigned short checksum(unsigned char *buf, int size);
void forge(void(*pro)(int *total_len), uint16_t mac_protocol, uint8_t ip_protocol); // forge template
void send_ip(void(*func)(int *total_len), int sock_raw, uint8_t protocol, int *total_len);
在forge函数中,通过传入相应的协议函数指针,即可生成一个对应协议的数据包,并且由于大多数网络层以上的协议都是基于IP的,故将send_ip
也写成一个模板。
例如要发送TCP,参数为:1:填充协议的函数指针;2:MAC的协议字段;3:IP的协议字段(ARP协议此参数填0即可)
forge(send_tcp, ETH_P_IP, IPPROTO_TCP);
其中forge()
实现如下
void forge(void(*pro)(int *total_len), uint16_t mac_protocol, uint8_t ip_protocol){
int sock_raw = sock_raw = socket(AF_PACKET,SOCK_RAW,ETH_P_IP);
if(sock_raw == -1)
printf("error in socket\n");
send_buff = (unsigned char*)malloc(64); // increase in case of large data.
memset(send_buff, 0, 64);
int total_len = 0;
get_eth_index(sock_raw); // interface number
get_mac(sock_raw, mac_protocol, &total_len);
if(mac_protocol == ETH_P_ARP) pro(&total_len);
else send_ip(pro, sock_raw, ip_protocol, &total_len);
struct sockaddr_ll sadr_ll;
sadr_ll.sll_ifindex = ifreq_idx.ifr_ifindex;
sadr_ll.sll_halen = ETH_ALEN;
for(int i = 0; i < 6; i++)
sadr_ll.sll_addr[i] = dst_mac[i];
int cnt = 1;
printf("sending...\n");
while(cnt-- > 0){
int send_len = sendto(sock_raw, send_buff, 64, 0, (const struct sockaddr*)&sadr_ll, sizeof(struct sockaddr_ll));
if(send_len < 0){
printf("error in sending....sendlen = %d....errno = %d\n", send_len, errno);
break;
}
}
close(sock_raw);
}
1.UDP packet forgery
void send_udp(int *total_len){
printf("udp packaging start ... \n");
struct udphdr *uh = (struct udphdr *)(send_buff + sizeof(struct iphdr) + sizeof(struct ethhdr));
uh->source = htons(23451);
uh->dest = htons(23452);
uh->check = 0; //Many OSes ignore this field , so we do not calculate it.
*total_len += sizeof(struct udphdr);
uh->len = htons((*total_len - sizeof(struct iphdr) - sizeof(struct ethhdr)));
printf("udp packaging start ... \n");
}
2.TCP packet forgery
由于TCP的checksum需要添加伪首部才能计算正确,故在头文件定义伪首部
struct psd_hdr{
unsigned int src_ipaddr;
unsigned int dst_ipaddr;
unsigned char nop;
unsigned char protocol;
unsigned short tcp_len;
};
TCP_forge.c
如下
void send_tcp(int *total_len){
struct tcphdr *th = (struct tcphdr *)(send_buff + sizeof(struct iphdr) + sizeof(struct ethhdr));
printf("tcp packaging start ... \n");
//write udp_header
th->th_sport = htons(2333);
th->th_dport = htons(80);
th->th_seq = htons(0);
th->th_ack = htons(0);
th->th_off = sizeof (struct tcphdr) / 4;
th->th_flags = TH_SYN;
th->th_win = htons(4096);
// define pseudo header for tcp checksum
struct psd_hdr psd;
psd.src_ipaddr = inet_addr(src_ip);
psd.dst_ipaddr = inet_addr(dst_ip);
psd.nop = 0;
psd.protocol = 6;
psd.tcp_len = htons(sizeof (struct tcphdr));
unsigned char cur[1000];
memcpy(cur, &psd, sizeof(struct psd_hdr));
memcpy(cur + sizeof (struct psd_hdr), th, sizeof(struct tcphdr));
th->th_sum = htons(checksum(cur, sizeof(struct tcphdr) + sizeof (struct psd_hdr)));
*total_len += sizeof(struct tcphdr);
printf("tcp packaging done ... \n");
}
3.ICMP packet forgery
由于struct icmp中含有union,为了方便起见,定义宏
// define icmp union
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
ICMP_forge.c
实现如下
void send_icmp(int *total_len){
printf("icmp packaging start ... \n");
struct icmp *ih = (struct icmp *)(send_buff + sizeof(struct iphdr) + sizeof(struct ethhdr));
ih->icmp_type = ICMP_ECHO;
ih->icmp_code = 0;
ih->icmp_cksum = htons(checksum((unsigned char *)(send_buff + sizeof (struct ethhdr) + sizeof (struct iphdr)), sizeof (struct icmp)));
ih->icmp_id = 0;
ih->icmp_seq = 0;
*total_len += sizeof(struct icmp);
printf("icmp packaging done ... \n");
}
4.ARP packet forgery
由于ARP
与IP
一样都是网络层协议,故在MAC
层需要将protocol
改为ETH_P_ARP
。
并且ARP协议的头部定义需要在
<netinet/if_ether.h>
头文件下找,而非<net/if_arp.h>
ARP_forge.c
定义如下
void send_arp(int *total_len){
printf("arp packaging start ... \n");
struct ether_arp *ah = (struct ether_arp *)(send_buff + sizeof (struct ethhdr));
str2ip(src_ip, ah->arp_spa);
str2ip(dst_ip, ah->arp_tpa);
for(int i = 0; i < 6; i++){
ah->arp_sha[i] = (unsigned char)(ifreq_mac.ifr_hwaddr.sa_data[i]);
ah->arp_tha[i] = (unsigned char)0x00;
}
ah->ea_hdr.ar_hrd = htons(0x01);
ah->ea_hdr.ar_pro = htons(ETH_P_IP);
ah->ea_hdr.ar_hln = ETH_ALEN;
ah->ea_hdr.ar_pln = 0x04;
ah->ea_hdr.ar_op = htons(ARPOP_REQUEST);
*total_len += sizeof (struct ether_arp);
printf("arp packaging done ... \n");
}
Part E:Design your own MAC layer protocol
文件结构:两个主机源代码大部分相同
|-- final
|-- protocol.h // define struct own_hdr and interface for send or receive
|-- send.c
|-- receive.c
|-- main.c
自定义了一个以太网头部格式如下,头部后面即要发送的数据
struct own_hdr{
unsigned char dst_mac[6];
unsigned char src_mac[6];
};
分别定义send.c/receive.c用来实现发送和接收的方法
// send
void get_eth_index();
void get_own_mac(unsigned char *buffer, unsigned char dst_mac[]);
void send_data(unsigned char *buffer);
// receive
void packet_print(unsigned char* buffer, int buffer_len);
void own_mac_header(unsigned char *buffer);
bool filterByMacAddress(unsigned char *buffer, unsigned char mac_addr[], int type);
bool equal(unsigned char *dst, unsigned char *src);
void get_data(unsigned char *buffer);
在主函数中,创建两个raw socket分别用来发送和接收数据包,主机A先发送,未收到主机B的回复之前不会再次发送,主机B同理。运行结果如下