linux发送一帧以太网包,用于TCP->HTTP的GET请求

本文详细介绍了如何使用C++编程语言构建并发送一个HTTP GET请求,包括以太网头、IP头、TCP头及HTTP数据的构建过程。通过具体的代码示例,读者可以学习到如何设置网络接口、目标地址,以及如何计算校验和,最终实现数据包的发送。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了简化流程,暂不做三次握手的过程,直接发单个HTTP GET请求的数据包.

思路就是,以太网头 + ip头 + tcp头 + http数据

用telnet测试

away@aways-iMac:~$ telnet baidu.com 80
Trying 123.125.115.110...
Connected to baidu.com.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 200 OK
Date: Fri, 04 Jan 2019 01:36:33 GMT
Server: Apache
Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
ETag: "51-47cf7e6ee8400"
Accept-Ranges: bytes
Content-Length: 81
Cache-Control: max-age=86400
Expires: Sat, 05 Jan 2019 01:36:33 GMT
Connection: Close
Content-Type: text/html

<html>
<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
</html>
Connection closed by foreign host.

实现代码如下

// MyTcp.h

#ifndef my_tcp_h
#define my_tcp_h

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_packet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <arpa/inet.h>

#include <string>
#include <iostream>

struct psdhdr {
	uint32_t src_addr;
	uint32_t dst_addr;
	uint8_t zero;
	uint8_t protocol;
	uint16_t tcp_len;
};


class MyTcp
{
public:
	MyTcp();
	~MyTcp();
	void setNic(std::string nic, int src_port);
	void setDst(std::string dst_ip, int dst_port);
	int send(std::string data);
private:
	int sockfd;
	struct sockaddr_ll dst_sock_addr;
	struct ether_header eth;
	struct iphdr iph;
	struct tcphdr tcph;
	struct psdhdr psdh;

	int src_addr;
	int dst_addr;

	uint16_t getCkSum(uint16_t *addr, int len);


};


#endif
//MyTcp.cpp

#include "MyTcp.h"




MyTcp::MyTcp() 
{
	sockfd = socket(AF_PACKET, SOCK_RAW, 0);
	if (sockfd == -1)
	{
		perror("socket");
		exit(1);
	}
}

MyTcp::~MyTcp()
{

}

void MyTcp::setNic(std::string nic, int src_port)
{
	struct ifreq if_index, if_mac, if_ip;
	bzero(&if_index, sizeof(struct ifreq));
	bzero(&if_mac, sizeof(struct ifreq));
	bzero(&if_ip, sizeof(struct ifreq));
	strcpy(if_index.ifr_name, nic.c_str());
	strcpy(if_mac.ifr_name, nic.c_str());
	strcpy(if_ip.ifr_name, nic.c_str());

	if (ioctl(sockfd, SIOCGIFINDEX, &if_index) < 0)
	{
		perror("siocgifindex");
		exit(1);
	}
	if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
	{
		perror("siocgifhwaddr");
		exit(1);
	}
	if (ioctl(sockfd, SIOCGIFADDR, &if_ip) < 0)
	{
		perror("siocgifaddr");
		exit(1);
	}
	for (int i = 0; i< 6; i++)
		eth.ether_shost[i] = if_mac.ifr_hwaddr.sa_data[i];
	eth.ether_type = htons(ETH_P_IP);

	src_addr = ((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr.s_addr;

	tcph.source = htons(src_port);

	bzero(&dst_sock_addr, sizeof(dst_sock_addr));
	dst_sock_addr.sll_ifindex = if_index.ifr_ifindex;
	dst_sock_addr.sll_halen = ETH_ALEN;
	dst_sock_addr.sll_protocol = ETH_P_IP;
}

void MyTcp::setDst(std::string dst_ip, int dst_port) 
{
	dst_addr = inet_addr(dst_ip.c_str());

	eth.ether_dhost[0] = 0xd0;
	eth.ether_dhost[1] = 0x17;
	eth.ether_dhost[2] = 0xc2;
	eth.ether_dhost[3] = 0xd3;
	eth.ether_dhost[4] = 0xb5;
	eth.ether_dhost[5] = 0xc9;

	iph.ihl = 5;
	iph.version = 4;
	iph.tos = IPTOS_LOWDELAY;
	iph.id = htons(54321);
	iph.ttl = 64;
	iph.protocol = IPPROTO_TCP;
	iph.saddr = src_addr;
	iph.daddr = dst_addr;
	iph.tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
	iph.check = 0;

	tcph.dest = htons(dst_port);
	tcph.seq = 0x0;
	tcph.ack_seq = 0x0;
	tcph.doff = 5;
	tcph.res1 = 0;
	tcph.urg = 0;
	tcph.ack = 0;
	tcph.psh = 1;
	tcph.rst = 0;
	tcph.syn = 0;
	tcph.fin = 0;
	tcph.window = htons(155);
	tcph.check = 0;
	tcph.urg_ptr = 0;

	psdh.src_addr = src_addr;
	psdh.dst_addr = dst_addr;
	psdh.zero = 0;
	psdh.protocol = IPPROTO_TCP;
	// psdh.tcp_len = htons(sizeof(struct tcphdr));
}

int MyTcp::send(std::string data) 
{
	int packet_len, psd_packet_len;
	char * packet, * psd_packet;

	packet_len = sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr) + data.size();
	psd_packet_len = sizeof(struct psdhdr) + sizeof(struct tcphdr) + data.size();
	packet = (char *)malloc(packet_len);
	if (packet == NULL)
	{
		perror("out of memory");
		exit(1);
	}
	psd_packet = (char *)malloc(psd_packet_len);
	if (psd_packet == NULL)
	{
		free(packet);
		perror("out of memory");
		exit(1);
	}
	iph.tot_len = htons(packet_len - sizeof(eth));
	iph.check = getCkSum((uint16_t*)&iph, sizeof(iphdr));  // /2?

	psdh.tcp_len = htons(sizeof(tcph) + data.size());
	memset(psd_packet, 0, psd_packet_len);
	memcpy(psd_packet, (char *)&psdh, sizeof(psdh));
	memcpy(psd_packet + sizeof(psdh), (char *)&tcph, sizeof(tcph));
	if (!data.empty())
	{
		memcpy(psd_packet + sizeof(psdh) + sizeof(tcph), data.c_str(), data.size());
	}
	tcph.check = getCkSum((uint16_t *)psd_packet, psd_packet_len);

	std::cout << "tcp cksum: " << tcph.check <<std::endl;


	memset(packet, 0, packet_len);
	memcpy(packet, (char *)&eth, sizeof(eth));
	memcpy(packet + sizeof(eth), (char *)&iph, sizeof(iph));
	memcpy(packet + sizeof(eth) + sizeof(iph), (char *)&tcph, sizeof(tcph));
	if (!data.empty())
	{
		memcpy(packet + packet_len - data.size(), data.c_str(), data.size());	
	}

	if (sendto(sockfd, packet, packet_len, 0, (struct sockaddr *)&dst_sock_addr,sizeof(dst_sock_addr)) < 0)
	{
		// perror("send failed");
		std::cout << "send failed\n";
	}

	free(packet);
	free(psd_packet);
	return 0;
}



uint16_t MyTcp::getCkSum(uint16_t *addr, int len)
{
	int				nleft = len;
	uint32_t		sum = 0;
	uint16_t		*w = addr;
	uint16_t		answer = 0;
	
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}
	
	if (nleft == 1) {
		*(unsigned char *)(&answer) = *(unsigned char *)w ;
		sum += answer;
	}
	
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return(answer);
}
// main.cpp

#include "MyTcp.h"


int main()
{
	MyTcp mytcp;
	mytcp.setNic("ens33", 75737);
	mytcp.setDst("192.168.88.222", 80);
	mytcp.send("GET / HTTP/1.0\r\n\r\n");
}

抓包结果如下:

tcpdump -i ens33 host 192.168.88.222 and host 192.168.88.223 -e -v and tcp 

 

11:07:29.909750 00:0c:29:a2:2f:82 (oui Unknown) > d0:17:c2:d3:b5:c9 (oui Unknown), ethertype IPv4 (0x0800), length 72: (tos 0x10, ttl 64, id 54321, offset 0, flags [none], proto TCP (6), length 58)
    192.168.88.223.10201 > 192.168.88.222.http: Flags [P], cksum 0x7558 (correct), seq 0:18, win 155, length 18: HTTP, length: 18
    GET / HTTP/1.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值