现在的位置: 首页 > 综合 > 正文

原始套接字编程:raw socket

2018年10月03日 ⁄ 综合 ⁄ 共 9743字 ⁄ 字号 评论关闭

raw socket即原始套接字编程:

一、udp发送数据

1.1 代码

代码的意义是:执行dig @8.8.8.8 www.guowenyan.cn,抓包获取二进制信息。 利用raw socket发送该二进制信息,相当于执行了dig命令。

      sendto()

      send()/write(),需要connect()。 connect()只是指定目的ip,端口号不起作用,原始套接字中不存在端口号的概念。

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

using namespace std;

int main(int argc, char*argv[])
{
    int sockfd;
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);

  
    struct sockaddr_in addr_srv;
    bzero(&addr_srv, sizeof(struct sockaddr_in));
    addr_srv.sin_addr.s_addr = inet_addr("8.8.8.8");
    addr_srv.sin_family = AF_INET;
    addr_srv.sin_port = htons(53);
     
    char buf[42] = {0xe0, 0x5d, 0x00, 0x35, 0x00, 0x2a, 0xeb, 0x68, 0x7c, 0x3c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x09, 0x67, 0x75, 0x6f, 0x77, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x02, 0x63, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x01};
    int ret;

    //ret = sendto(sockfd, buf, 42, 0, (sockaddr*)&addr_srv, sizeof(struct sockaddr_in));

    connect(sockfd, (sockaddr*)&addr_srv, sizeof(struct sockaddr_in));
    ret = send(sockfd, buf, 42, 0);  
    //ret = write(sockfd, buf, 42);

    cout<<"ret:"<<ret<<endl;


    close(sockfd);

    return 0;
}

1.2 结果

二、发送UDP数据(自己填充IP、UDP头部)

2.1 代码

代码的意义是:执行dig @8.8.8.8 www.guowenyan.cn,抓包获取二进制信息。 利用raw socket发送该二进制信息,相当于执行了dig命令。

用到的日志代码部分,参照:http://blog.csdn.net/guowenyan001/article/details/17390109

raw_senddata.h:

////////////////////////////////////////////////////////////////
//
//Descript: send data with raw socket, only send tcp or udp data.
//  Author: guowenyan
//    Date: 2014.02.12
//
////////////////////////////////////////////////////////////////
#pragma once

#include <string>

typedef struct ip_hdr
{
	unsigned int ip_length:4;
	unsigned int ip_version:4;
	
	unsigned char ip_tos;
	unsigned short ip_tot_len;

	unsigned short ip_id;
	unsigned short ip_flags;
	
	unsigned char ip_ttl;
	unsigned char ip_protocol;
	unsigned short ip_cksum;
	
	unsigned int ip_source;
	
	unsigned int ip_dest;
}ip_hdr;


typedef struct udp_hdr
{
	unsigned short udp_sport;
	unsigned short udp_dport;

	unsigned short udp_len;
	unsigned short udp_cksum;
}udp_hdr;

typedef struct psd_header
{
	unsigned int psd_sip;     //source ip
	
	unsigned int psd_dip;     //destation ip
	
	unsigned char psd_mbz;    //0
	unsigned char psd_proto;  //protocol  (udp)
	unsigned short psd_len;   //length   (the length of udp header and udp data)
}psd_header;


class raw_senddata
{
public:
    raw_senddata(const std::string &filename, const std::string &srcip, const std::string &destip, const std::string &protocol, unsigned short sport, unsigned short dport);

    int senddata();

private:
    //read udp data from file.  "c0a8 1a75" -> "0xc0 0xa8 0x1a 0x75"
    int convert(unsigned char* str);
    int readfile(unsigned char *&buf, int &count);

    int parse_protocol();

    //计算校验和
    unsigned short ip_cksum(unsigned short *buf, int len);
    unsigned short udp_cksum(const psd_header* psdhdr, unsigned short *buf, int udp_len);

    //fill ip header and udp header.  psd_header是udp的伪首部,计算UDP校验和用。
    void fill_ip_hdr(ip_hdr* iphdr, unsigned short tot_len, unsigned char protocol, unsigned int source, unsigned int dest);
    void fill_udp_hdr(udp_hdr* udphdr, unsigned short sport, unsigned short dport, unsigned short len);
    void fill_psd_hdr(const ip_hdr* iphdr, const udp_hdr* udphdr, psd_header* psd, unsigned char protocol);

private:
    std::string m_filename;
    std::string m_srcip, m_destip;
    std::string m_protocol;
    unsigned short m_sport, m_dport;
};

raw_senddata.cpp:

////////////////////////////////////////////////////////////////
//
//Descript: send data with raw socket, only send tcp or udp data.
//  Author: guowenyan
//    Date: 2014.02.12
//
////////////////////////////////////////////////////////////////
#include "raw_senddata.h"
#include "log.h"
#include <fstream>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

using namespace std;


static const int g_ip_header_len  = 20;
static const int g_udp_header_len = 8;

raw_senddata::raw_senddata(const string &filename, const string &srcip, const string &destip, const string &protocol, unsigned short sport, unsigned short dport) 
    : m_filename(filename), m_srcip(srcip), m_destip(destip), m_protocol(protocol), m_sport(sport), m_dport(dport)
{

}

int raw_senddata::senddata()
{
    int sockfd = socket(AF_INET, SOCK_RAW, parse_protocol());
    if (sockfd < 0) 
    {
        LOG_DEBUG(mformat("socket error, sockfd: %d.", sockfd));
        return -1;
    }

	const int on = 1;
	setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));

	//read udp data from file.  "c0a8 1a75" -> "0xc0 0xa8 0x1a 0x75"
    unsigned char *buf = NULL;
    int count = 0;
    int ret = readfile(buf, count);
    if (ret < 0) 
    {
        LOG_DEBUG(mformat("read file error, ret: %d.", ret));
        return -2;
    }

	//fill ip header and udp header.
	unsigned int udp_len = g_udp_header_len + count;
	unsigned int tot_len = g_ip_header_len + udp_len;
	
    unsigned char *data_buf = new unsigned char[tot_len];
	
    ip_hdr* iphdr = (ip_hdr*)data_buf;
	fill_ip_hdr(iphdr, tot_len, parse_protocol(), inet_addr(m_srcip.c_str()), inet_addr(m_destip.c_str()));
	
	udp_hdr* udphdr = (udp_hdr*)(data_buf + g_ip_header_len);
	fill_udp_hdr(udphdr, m_sport, m_dport, udp_len);

	psd_header psdhdr;
	fill_psd_hdr(iphdr, udphdr, &psdhdr, parse_protocol());
	
    udphdr->udp_cksum = udp_cksum(&psdhdr, (unsigned short*)(data_buf + g_ip_header_len), udp_len);

	memcpy(data_buf + g_ip_header_len+ g_udp_header_len, buf, count);

    if (buf)
    {
        delete []buf;
        buf = NULL;
    }

	//send data.
	struct sockaddr_in addr_srv;
    bzero(&addr_srv, sizeof(struct sockaddr_in));
    addr_srv.sin_addr.s_addr = inet_addr(m_destip.c_str());
    addr_srv.sin_family = AF_INET;
    addr_srv.sin_port = htons(53);
	
    ret = sendto(sockfd, data_buf, tot_len, 0, (sockaddr*)&addr_srv, sizeof(struct sockaddr_in));  
    if (ret < 0) 
    {
        if (data_buf)
        {
            delete []data_buf;
            data_buf = NULL;
        }
        LOG_DEBUG(mformat("sendto error, ret: %d.", ret));
        return -3;
    }

    if (data_buf)
    {
        delete []data_buf;
        data_buf = NULL;
    }
    LOG_INFO(mformat("the data size of send is: %d.", ret));

    close(sockfd);

    return 0;
}


int raw_senddata::convert(unsigned char* str)
{
    if (NULL == str)
    {
        return -1;
    }

    unsigned int var = 0;
    for (; *str; ++str)
    {
        if ((*str>='A' && *str<='F') || (*str>='a' && *str<='f'))
        {
            unsigned char c = toupper(*str);
            var = (var<<4) + (c - 55);
        }
        else if (*str>='0' && *str<='9')
        {
            var = (var<<4) + (*str - '0');        
        }
    }
    return var;
}

int raw_senddata::readfile(unsigned char *&buf, int &count)
{
    fstream file(m_filename.c_str(), ios::in);
    if (!file)
    {
        LOG_DEBUG(mformat("open file: %s error.", m_filename.c_str()));
        return -1;
    }

    file.seekp(0, ios_base::end);
    int length = file.tellp();
    file.seekp(0, ios_base::beg);

    char *tmp = new char[length+1];
    file.read(tmp, length);
    tmp[length] = '\0';

    buf = new unsigned char[length/2 + 1];
    count = 0;
    for (int i=0; i<length; ++i)
    {
        unsigned char str[3] = {0};
        if ((tmp[i]>='a' && tmp[i]<='f') || (tmp[i]>='A' && tmp[i]<='F') || (tmp[i]>='0' && tmp[i]<='9'))
        {
            str[0] = tmp[i];
            while (++i < length)
            {
                if ((tmp[i]>='a' && tmp[i]<='f') || (tmp[i]>='A' && tmp[i]<='F') || (tmp[i]>='0' && tmp[i]<='9'))
                {
                    str[1] = tmp[i];
                    break;
                }
            }


            buf[count++] = convert(str);
        }
    }

    if (tmp)
    {
        delete []tmp;
        tmp = NULL;
    }

    return 0;
}


int raw_senddata::parse_protocol()
{
    if (0 == strcasecmp(m_protocol.c_str(), "tcp"))  
    {
        return IPPROTO_TCP;
    }
    else if (0 == strcasecmp(m_protocol.c_str(), "udp"))
    {
        return IPPROTO_UDP;
    }

    return IPPROTO_UDP;
}

unsigned short raw_senddata::ip_cksum(unsigned short *buf, int len)

{
    //将每个16bit求和,和为32bit
    unsigned int sum = 0;
    while( len > 1)
    {
        sum += *buf++;
        len -= 2;
    }

    //若长度为奇数字节,后面补0
    if(1 == len)
    {
        sum += *(unsigned char*)buf;
    }

    //将和32bit中,高16bit与低16bit相加,直到只有16bit
    while(sum>>16)  
    {
        sum = (sum>>16) + (sum&0xffff);
    }

    //取反
    return ~sum;
}

unsigned short raw_senddata::udp_cksum(const psd_header* psdhdr, unsigned short *buf, int udp_len)
{
    unsigned int psd_hdr_len = sizeof(psd_header);

	char udp_buf[psd_hdr_len + udp_len];
	memcpy(udp_buf, psdhdr, psd_hdr_len);
	memcpy(udp_buf + psd_hdr_len, buf+g_ip_header_len, udp_len);

    return ip_cksum((unsigned short*)udp_buf, psd_hdr_len + udp_len);
}

void raw_senddata::fill_ip_hdr(ip_hdr* iphdr, unsigned short tot_len, unsigned char protocol, unsigned int source, unsigned int dest)
{
    iphdr->ip_length = 5;
	iphdr->ip_version = 4;
	iphdr->ip_tos = 0;
	iphdr->ip_tot_len = htons(tot_len); //

	iphdr->ip_id = 0;
	iphdr->ip_flags = 0x40;

	iphdr->ip_ttl = 0x40;
	iphdr->ip_protocol = protocol;
	iphdr->ip_cksum = 0;

	iphdr->ip_source = source;
	iphdr->ip_dest = dest;

	iphdr->ip_cksum = ip_cksum((unsigned short *)iphdr, 20);
}

void raw_senddata::fill_udp_hdr(udp_hdr* udphdr, unsigned short sport, unsigned short dport, unsigned short len)
{
	udphdr->udp_sport = htons(sport);
	udphdr->udp_dport = htons(dport);

	udphdr->udp_len = htons(len);
	udphdr->udp_cksum = 0;
}

void raw_senddata::fill_psd_hdr(const ip_hdr* iphdr, const udp_hdr* udphdr, psd_header* psd, unsigned char protocol)
{
    psd->psd_sip = iphdr->ip_source;
	psd->psd_dip = iphdr->ip_dest;

	psd->psd_proto = protocol;
	psd->psd_mbz = 0;
	psd->psd_len = udphdr->udp_len;
}

sendpack.cpp:(main)

////////////////////////////////////////////////////////////////
//
//Descript: main file.  command line parameter.
//  Author: guowenyan
//    Date: 2014.02.12
//
////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>

#include "raw_senddata.h"
#include "log.h"

#include <boost/program_options.hpp>


using namespace std;
namespace po = boost::program_options;


int main(int argc, char*argv[])
{
    string filename, srcip, destip, protocol;
    unsigned short sport, dport;

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help messages")
        ("file,f", po::value<string>(&filename), "the name of data file")
        ("srcip,a", po::value<string>(&srcip), "source ip address")
        ("destip,b", po::value<string>(&destip), "destination ip address")
        ("protocol,p", po::value<string>(&protocol)->default_value("udp"), "the protocol of socket")
        ("sport,s", po::value<unsigned short>(&sport)->default_value(0), "the source port")
        ("dport,d", po::value<unsigned short>(&dport)->default_value(0), "the desation port");

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    if (vm.count("help"))
    {
        LOG_DEBUG(desc);
        return 0;
    }

    if (filename.empty() || srcip.empty() || destip.empty() || 0 == sport || 0 == dport)
    {
        LOG_DEBUG("invalid parameter. filename or srcip or destip is empty, or sport is 0 or dport is 0.");
        return -1;
    }

    LOG_INFO(mformat("filename: %s.", filename.c_str()));
	LOG_INFO(mformat("srcip: %s.", srcip.c_str()));
    LOG_INFO(mformat("destip: %s.", destip.c_str()));
    LOG_INFO(mformat("protocol: %s.", protocol.c_str()));
    LOG_INFO(mformat("sport: %d.", sport));
    LOG_INFO(mformat("dport: %d.", dport));

    raw_senddata raw_s(filename, srcip, destip, protocol, sport, dport);
    int ret = raw_s.senddata();
    if (ret < 0)
    {
        LOG_DEBUG(mformat("raw_senddata::senddata() error. ret: %d.", ret));
        LOG_DEBUG(desc);
        return -4;
    }

    return 0;
}

2.2 结果

执行命令:./sendpack -f aa.txt -a 192.168.26.117 -b 8.8.8.8 -s 47596 -d 53

抱歉!评论已关闭.