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; }
执行命令:./sendpack -f aa.txt -a 192.168.26.117 -b 8.8.8.8 -s 47596 -d 53