前段时间为了验证某个开源软件的硬件校验功能,需要自己写一个RAW socket 计算checksum,检查对端接收到这个包时,如果checksum不对,能否正常被过滤掉,估计很多人可能与我一样,有的时候需要这种小功能的软件,所以贡献一份源码:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>
using namespace std;
#define DATALEN 10
#define baselog(fmt, args...) printf("%s %s %d " fmt "\n", __func__, __FILE__, __LINE__, ##args)
class Rawsock {
public:
int sockfd;
unsigned short sport;
unsigned short dport;
unsigned int saddr;
unsigned int daddr;
void createsockfd();
int getsockfd();
unsigned short getsport();
unsigned short getdport();
void setsport(unsigned short port);
void setdport(unsigned short port);
unsigned int getdaddr();
unsigned int getsaddr();
void setdaddr(unsigned int addr);
void setsaddr(unsigned int addr);
int initlization_iphdr(struct iphdr *iphr, unsigned int saddr = 0, unsigned int daddr = 0);
int initlization_udphdr(struct udphdr *udphr, unsigned short sport = 0, unsigned short dport = 0);
unsigned short int ipv4_header_cksum(const struct iphdr *ipv4_hdr);
int sethdrincl();
};
#include "rawsock.h"
void Rawsock::createsockfd()
{
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (sockfd < 0) {
baselog("create socket failed.");
exit(1);
}
}
int Rawsock::sethdrincl()
{
int value = 1;
return setsockopt(sockfd,IPPROTO_IP, IP_HDRINCL, &value, sizeof(value));
}
int Rawsock::getsockfd()
{
return sockfd;
}
unsigned short Rawsock::getsport()
{
return sport;
}
unsigned short Rawsock::getdport()
{
return dport;
}
unsigned int Rawsock::getdaddr()
{
return daddr;
}
unsigned int Rawsock::getsaddr()
{
return saddr;
}
void Rawsock::setsport(unsigned short port)
{
sport = port;
}
void Rawsock::setdport(unsigned short port)
{
dport = port;
}
void Rawsock::setsaddr(unsigned int addr)
{
saddr = addr;
}
void Rawsock::setdaddr(unsigned int addr)
{
daddr = addr;
}
int Rawsock::initlization_iphdr(struct iphdr *iphr, unsigned int saddr, unsigned int daddr)
{
if (iphr == NULL || !saddr || !daddr)
return -1;
iphr->ihl = 5; /*ip head len,include ip option*/
iphr->version = 4; /*ipv4*/
iphr->tos = 0;
iphr->tot_len = htons((iphr->ihl << 2) + sizeof(struct udphdr) + DATALEN);
iphr->id = 0;
iphr->frag_off = htons(0x4000); /*set do not fragmet flag*/
iphr->ttl = 32;
iphr->protocol = IPPROTO_UDP;
iphr->check = 0; /*must set to 0, before real checksum*/
/*saddr and daddr should be network byte order*/
iphr->saddr = saddr;
iphr->daddr = daddr;
return 0;
}
int Rawsock::initlization_udphdr(struct udphdr *udphr, unsigned short sport, unsigned short dport)
{
if (udphr == NULL || !sport || !dport)
return -1;
/*sport and dport should be network byte order*/
udphr->source = sport;
udphr->dest = dport;
udphr->len = htons(sizeof(struct udphdr) + DATALEN);
udphr->check = 0;
return 0;
}
uint16_t __rte_raw_cksum_reduce(uint32_t sum)
{
sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
return (uint16_t)sum;
}
uint32_t __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
{
/* workaround gcc strict-aliasing warning */
uintptr_t ptr = (uintptr_t)buf;
const uint16_t *u16 = (const uint16_t *)ptr;
while (len >= (sizeof(*u16) * 4)) {
sum += u16[0];
sum += u16[1];
sum += u16[2];
sum += u16[3];
len -= sizeof(*u16) * 4;
u16 += 4;
}
while (len >= sizeof(*u16)) {
sum += *u16;
len -= sizeof(*u16);
u16 += 1;
}
/* if length is in odd bytes */
if (len == 1)
sum += *((const uint8_t *)u16);
return sum;
}
uint16_t rte_raw_cksum(const void *buf, size_t len)
{
uint32_t sum;
sum = __rte_raw_cksum(buf, len, 0);
return __rte_raw_cksum_reduce(sum);
}
uint16_t Rawsock::ipv4_header_cksum(const struct iphdr *ipv4_hdr)
{
uint16_t cksum;
cksum = rte_raw_cksum(ipv4_hdr, sizeof(struct iphdr));
return ((cksum == 0xffff) ? cksum : ~cksum);
}
#include <iostream>
#include "rawsock.h"
const char *saddr_ip = "183.60.73.18";
const char *daddr_ip = "183.60.73.17";
const unsigned short sport = 3332;
const unsigned short dport = 3333;
int main(int argc, char **argv)
{
Rawsock obj;
int pkt_len = 0;
struct iphdr *iphr = NULL;
struct udphdr *udphr = NULL;
char *data_buff = NULL;
unsigned int saddr = inet_addr(saddr_ip);
unsigned int daddr = inet_addr(daddr_ip);
unsigned short s_port = htons(sport);
unsigned short d_port = htons(dport);
obj.setsport(s_port);
obj.setdport(d_port);
obj.setsaddr(saddr);
obj.setdaddr(daddr);
obj.createsockfd();
#ifdef __HDRINCL__
baselog("defined __HDRINCL__, need to build ip header.");
#else
baselog("not defined __HDRINCL__, just build udp header.");
#endif
#ifdef __HDRINCL__
if (obj.sethdrincl() < 0){
baselog("set hdrincl failed.");
}
#endif
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = obj.getdaddr();
servaddr.sin_port = obj.getdport();
unsigned char mpkt_buf[1024] = {0};
#ifdef __HDRINCL__
iphr = (struct iphdr *)mpkt_buf;
obj.initlization_iphdr(iphr, obj.getsaddr(), obj.getdaddr());
iphr->check = obj.ipv4_header_cksum(iphr);
udphr = (struct udphdr *)(iphr + 1);
pkt_len = ntohs(iphr->tot_len);
#else
udphr = (struct udphdr *)mpkt_buf;
pkt_len = sizeof(struct udphdr) + DATALEN;
#endif
obj.initlization_udphdr(udphr, obj.getsport(), obj.getdport());
data_buff = (char *)(udphr + 1);
for(int i = 0; i < DATALEN; i ++)
*data_buff = i + 'a';
int ret = sendto(obj.getsockfd(), mpkt_buf, pkt_len, 0,(struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));
if (ret < 0)
baselog("send pkt failed.");
return 0;
}
编译:
g++ rawsock.cpp main.cpp -o main -D__HDRINCL__
浙公网安备 33010602011771号