前段时间为了验证某个开源软件的硬件校验功能,需要自己写一个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__

 

posted on 2015-09-09 19:37  jensonone  阅读(321)  评论(0)    收藏  举报