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