用boost庫實現traceroute小工具

????? 參考了網上幾個 traceroute的實現版本,存在一些缺陷,比如沒有做超時處理,或者只能在window下使用。自己用boost實現了一個traceroute小工具,在window下正常運行。

????? 先來看下面實現的原理。這些說明來自維基百科。traceroute,現代Linux系統稱為tracepath,Windows系統稱為tracert,是一種電腦網絡工具。它可顯示數據包在IP網絡經過的路由器的IP地址。 程序利用增加存活時間(TTL)值來實現其功能的。每當數據包經過一個路由器,其存活時間就會減1。當其存活時間是0時,主機便取消數據包,并傳送一個ICMP TTL數據包給原數據包的發出者。

????? 下面是具體實現的源代碼:

?

  1 //
  2 // traceroute.cpp
  3 // ~~~~~~~~
  4 //
  5 // BoSheng Lu 2013-04-25
  6 //
  7 // Version 1.0.
  8 //
  9 
 10 #include <boost/asio.hpp>
 11 #include <boost/bind.hpp>
 12 #include<boost/thread.hpp>
 13 #include <istream>
 14 #include <iostream>
 15 #include<iomanip>
 16 #include<string> 
 17 #include <ostream>
 18 
 19 #include "icmp_header.hpp"
 20 #include "ipv4_header.hpp"
 21 
 22 using boost::asio::ip::icmp;
 23 using boost::asio::deadline_timer;
 24 namespace posix_time = boost::posix_time;
 25 
 26 class traceroute
 27 {
 28 public:
 29     traceroute(boost::asio::io_service& io_service, const char* destination)
 30         : resolver_(io_service), socket_(io_service, icmp::v4()),
 31         sequence_number_(0), max_hop_(30)
 32     {
 33         icmp::resolver::query query(icmp::v4(), destination, "");
 34         destination_ = *resolver_.resolve(query);
 35 
 36         std::cout << "\nTracing route to " << destination 
 37         << " [" << destination_.address().to_string() << "]"
 38         << " with a maximum of " << max_hop_ << " hops.\n" << std::endl;
 39 
 40 #if defined(BOOST_WINDOWS)
 41         int timeout = 5000;
 42         if( setsockopt(socket_.native(), SOL_SOCKET, SO_RCVTIMEO, 
 43             (const char*)&timeout, sizeof(timeout)))
 44         {
 45              std::cout << "RCVTIMEO not set properly." << std::endl;
 46             throw std::runtime_error("RCVTIMEO not set properly");
 47         }
 48 #else
 49         struct timeval tv;
 50         tv.tv_sec  = 5; 
 51         tv.tv_usec = 0;         
 52         if( setsockopt(socket_.native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
 53         {
 54             std::cout << "RCVTIMEO not set properly." << std::endl;
 55             throw std::runtime_error("RCVTIMEO not set properly");
 56         }
 57 #endif
 58 
 59         reach_dest_host_ = false;
 60         int ttl = 1;
 61         while (!reach_dest_host_ && max_hop_--)
 62         {
 63             const boost::asio::ip::unicast::hops option(ttl);
 64             socket_.set_option(option);
 65 
 66             boost::asio::ip::unicast::hops op;
 67             socket_.get_option(op);
 68             if( ttl !=  op.value() )
 69             {
 70                 std::cout << "TTL not set properly. Should be "
 71                     << ttl << " but was set to "
 72                     << op.value() << '.' << std::endl;
 73                 throw std::runtime_error("TTL not set properly");        
 74             }
 75 
 76             std::cout << std::setw(3) << ttl << std::flush;
 77             start_send();
 78             start_receive();
 79          
 80             ttl++;
 81         }//while
 82     }
 83 
 84 private:
 85     void start_send()
 86     {
 87         std::string body("\"Hello!\" from Asio ping.");
 88 
 89         // Create an ICMP header for an echo request.
 90         icmp_header echo_request;
 91         echo_request.type(icmp_header::echo_request);
 92         echo_request.code(0);
 93         echo_request.identifier(get_identifier());
 94         echo_request.sequence_number(++sequence_number_);
 95         compute_checksum(echo_request, body.begin(), body.end());
 96 
 97         // Encode the request packet.
 98         boost::asio::streambuf request_buffer;
 99         std::ostream os(&request_buffer);
100         os << echo_request << body;
101 
102         // Send the request.
103         time_sent_ = posix_time::microsec_clock::universal_time();
104         socket_.send_to(request_buffer.data(), destination_);  
105     }
106 
107 
108     void start_receive()
109     {
110         // Discard any data already in the buffer.
111         reply_buffer_.consume(reply_buffer_.size());
112 
113         // Wait for a reply. We prepare the buffer to receive up to 64KB.
114         boost::system::error_code ec;
115         boost::asio::socket_base::message_flags flags = 0;
116         size_t len = socket_.receive(reply_buffer_.prepare(65536), flags, ec);
117     
118         handle_receive(len, ec);
119     }
120 
121     void handle_receive(std::size_t length, boost::system::error_code& ec)
122     {
123         // The actual number of bytes received is committed to the buffer so that we
124         // can extract it using a std::istream object.
125         reply_buffer_.commit(length);
126 
127         // Decode the reply packet.
128         std::istream is(&reply_buffer_);
129         ipv4_header ipv4_hdr;
130         is >> ipv4_hdr;
131 
132         if(ec)
133         {
134             std::cout << std::setw(9) << '*' << '\t' << "Request timed out." << std::endl;
135             return;
136         }
137     
138         posix_time::ptime now = posix_time::microsec_clock::universal_time();
139         long long dwRoundTripTime = (now - time_sent_).total_milliseconds();
140 
141         if(dwRoundTripTime)
142         {
143             std::cout << std::setw(6) << dwRoundTripTime << " ms"  << std::flush;
144         }
145         else
146         {
147             std::cout << std::setw(6) << "<1" << " ms" << std::flush;
148         }
149         
150         boost::this_thread::sleep(boost::posix_time::seconds(2)); 
151     
152         std::cout << '\t' << ipv4_hdr.source_address() << std::endl;
153 
154         // Print out some information about the reply packet.
155         if( ipv4_hdr.source_address().to_string() == destination_.address().to_string() )
156         {
157             reach_dest_host_ = true;
158             std::cout << std::endl;
159             std::cout << std::endl;
160             std::cout << "traceroute sucess!" << std::endl;
161 
162             icmp_header icmp_hdr;
163             is >> icmp_hdr;
164 
165             if (is && icmp_hdr.type() == icmp_header::echo_reply
166                 && icmp_hdr.identifier() == get_identifier()
167                 && icmp_hdr.sequence_number() == sequence_number_)
168             {
169                 // Print out some information about the reply packet.
170                 std::cout << length - ipv4_hdr.header_length()
171                  << " bytes from " << ipv4_hdr.source_address()
172                 << ": icmp_seq=" << icmp_hdr.sequence_number()
173                 << ", ttl=" << ipv4_hdr.time_to_live()
174                 << ", time=" << dwRoundTripTime << " ms"
175                 << std::endl;
176             }
177         }
178      }
179 
180     static unsigned short get_identifier()
181     {
182 #if defined(BOOST_WINDOWS)
183         return static_cast<unsigned short>(::GetCurrentProcessId());
184 #else
185         return static_cast<unsigned short>(::getpid());
186 #endif
187     }
188 
189     icmp::resolver resolver_;
190     icmp::endpoint destination_;
191     icmp::socket socket_;
192     unsigned short sequence_number_;
193     posix_time::ptime time_sent_;
194     boost::asio::streambuf reply_buffer_;
195     bool reach_dest_host_;
196     std::size_t max_hop_;
197 };
198 
199 int main(int argc, char* argv[])
200 {
201     try
202     {
203         if(argc != 2)
204         {
205             std::cerr << "Usage: ping <host>" << std::endl;
206 #if !defined(BOOST_WINDOWS)
207             std::cerr << "(You may need to run this program as root.)" << std::endl;
208 #endif
209             return 1;
210         }
211 
212         boost::asio::io_service io_service;
213         traceroute p(io_service, argv[1]);
214         io_service.run();
215     }
216     catch (std::exception& e)
217     {
218         std::cerr << "Exception: " << e.what() << std::endl;
219     }
220 }

?

?

??? ? ?這個源碼實現使用了boost庫附帶的boost asio使用示例中的代碼,下面也將這個例子中使用到的代碼附上,方便使用。至于boost庫的編譯使用另請參考其他的文章。

????? 下面是ipv4_header.hpp

//
// ipv4_header.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef IPV4_HEADER_HPP
#define IPV4_HEADER_HPP#include <algorithm>
#include <boost/asio/ip/address_v4.hpp>// Packet header for IPv4.
//
// The wire format of an IPv4 header is:
// 
// 0               8               16                             31
// +-------+-------+---------------+------------------------------+      ---
// |       |       |               |                              |       ^
// |version|header |    type of    |    total length in bytes     |       |
// |  (4)  | length|    service    |                              |       |
// +-------+-------+---------------+-+-+-+------------------------+       |
// |                               | | | |                        |       |
// |        identification         |0|D|M|    fragment offset     |       |
// |                               | |F|F|                        |       |
// +---------------+---------------+-+-+-+------------------------+       |
// |               |               |                              |       |
// | time to live  |   protocol    |       header checksum        |   20 bytes
// |               |               |                              |       |
// +---------------+---------------+------------------------------+       |
// |                                                              |       |
// |                      source IPv4 address                     |       |
// |                                                              |       |
// +--------------------------------------------------------------+       |
// |                                                              |       |
// |                   destination IPv4 address                   |       |
// |                                                              |       v
// +--------------------------------------------------------------+      ---
// |                                                              |       ^
// |                                                              |       |
// /                        options (if any)                      /    0 - 40
// /                                                              /     bytes
// |                                                              |       |
// |                                                              |       v
// +--------------------------------------------------------------+      ---class ipv4_header
{
public:ipv4_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }unsigned char version() const { return (rep_[0] >> 4) & 0xF; }unsigned short header_length() const { return (rep_[0] & 0xF) * 4; }unsigned char type_of_service() const { return rep_[1]; }unsigned short total_length() const { return decode(2, 3); }unsigned short identification() const { return decode(4, 5); }bool dont_fragment() const { return (rep_[6] & 0x40) != 0; }bool more_fragments() const { return (rep_[6] & 0x20) != 0; }unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; }unsigned int time_to_live() const { return rep_[8]; }unsigned char protocol() const { return rep_[9]; }unsigned short header_checksum() const { return decode(10, 11); }boost::asio::ip::address_v4 source_address() const{boost::asio::ip::address_v4::bytes_type bytes= { { rep_[12], rep_[13], rep_[14], rep_[15] } };return boost::asio::ip::address_v4(bytes);}boost::asio::ip::address_v4 destination_address() const{boost::asio::ip::address_v4::bytes_type bytes= { { rep_[16], rep_[17], rep_[18], rep_[19] } };return boost::asio::ip::address_v4(bytes);}friend std::istream& operator>>(std::istream& is, ipv4_header& header){is.read(reinterpret_cast<char*>(header.rep_), 20);if (header.version() != 4)is.setstate(std::ios::failbit);std::streamsize options_length = header.header_length() - 20;if (options_length < 0 || options_length > 40)is.setstate(std::ios::failbit);elseis.read(reinterpret_cast<char*>(header.rep_) + 20, options_length);return is;}private:unsigned short decode(int a, int b) const{ return (rep_[a] << 8) + rep_[b]; }unsigned char rep_[60];
};#endif // IPV4_HEADER_HPP

?????? 下面是icmp_header.hpp

//
// icmp_header.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef ICMP_HEADER_HPP
#define ICMP_HEADER_HPP#include <istream>
#include <ostream>
#include <algorithm>// ICMP header for both IPv4 and IPv6.
//
// The wire format of an ICMP header is:
// 
// 0               8               16                             31
// +---------------+---------------+------------------------------+      ---
// |               |               |                              |       ^
// |     type      |     code      |          checksum            |       |
// |               |               |                              |       |
// +---------------+---------------+------------------------------+    8 bytes
// |                               |                              |       |
// |          identifier           |       sequence number        |       |
// |                               |                              |       v
// +-------------------------------+------------------------------+      ---class icmp_header
{
public:enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,timestamp_request = 13, timestamp_reply = 14, info_request = 15,info_reply = 16, address_request = 17, address_reply = 18 };icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }unsigned char type() const { return rep_[0]; }unsigned char code() const { return rep_[1]; }unsigned short checksum() const { return decode(2, 3); }unsigned short identifier() const { return decode(4, 5); }unsigned short sequence_number() const { return decode(6, 7); }void type(unsigned char n) { rep_[0] = n; }void code(unsigned char n) { rep_[1] = n; }void checksum(unsigned short n) { encode(2, 3, n); }void identifier(unsigned short n) { encode(4, 5, n); }void sequence_number(unsigned short n) { encode(6, 7, n); }friend std::istream& operator>>(std::istream& is, icmp_header& header){ return is.read(reinterpret_cast<char*>(header.rep_), 8); }friend std::ostream& operator<<(std::ostream& os, const icmp_header& header){ return os.write(reinterpret_cast<const char*>(header.rep_), 8); }private:unsigned short decode(int a, int b) const{ return (rep_[a] << 8) + rep_[b]; }void encode(int a, int b, unsigned short n){rep_[a] = static_cast<unsigned char>(n >> 8);rep_[b] = static_cast<unsigned char>(n & 0xFF);}unsigned char rep_[8];
};template <typename Iterator>
void compute_checksum(icmp_header& header,Iterator body_begin, Iterator body_end)
{unsigned int sum = (header.type() << 8) + header.code()+ header.identifier() + header.sequence_number();Iterator body_iter = body_begin;while (body_iter != body_end){sum += (static_cast<unsigned char>(*body_iter++) << 8);if (body_iter != body_end)sum += static_cast<unsigned char>(*body_iter++);}sum = (sum >> 16) + (sum & 0xFFFF);sum += (sum >> 16);header.checksum(static_cast<unsigned short>(~sum));
}#endif // ICMP_HEADER_HPP

?

轉載于:https://www.cnblogs.com/spruce/archive/2013/04/26/3044233.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/259807.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/259807.shtml
英文地址,請注明出處:http://en.pswp.cn/news/259807.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Win系統利用本地安全策略全面禁止360等軟件的安裝與運行-1

這個理論應該也可以用在域對下設域用戶上.各位不知道有沒有這種經歷&#xff0c;機子讓別人玩了一上午&#xff0c;回來發現&#xff0c;自己干干凈凈的系統多了一堆某某安全助手&#xff0c;某某殺毒&#xff0c;某某手機助手等等&#xff0c;最可恨的還是不知一系列的&#x…

php配置文件php.ini的詳細解析(續)

file_uploads On //是否允許文件上傳 upload_tmp_dir "d:/wamp/tmp" //上傳文件的臨時目錄&#xff0c;默認為“/wamp/tm…

服務器iis7.5 配置文件,使用注冊表項 - Internet Information Services | Microsoft Docs

Internet 信息服務使用的注冊表項的說明07/21/2020本文內容本文介紹了 Microsoft Internet Information Services (IIS) 在 Windows 上使用的注冊表項。原始產品版本&#xff1a; Internet information Services原始 KB 數&#xff1a; 954864簡介本文還包含有關如何修改注…

access考試素材_NCRE考試當天常見問題處理辦法及各科目注意事項大匯總

溫馨提醒為了方便大家在21-22號討論考試抽中的題目&#xff0c;請自覺加入QQ群&#xff1a;776167039考試當天常見問題及處理辦法大匯總問題一&#xff1a;考試當天忘記帶身份證和準考證原因&#xff1a;這種情況&#xff0c;要么是忘了&#xff0c;要么真沒有提前領到準考證。…

騰訊開源手游熱更新方案,Unity3D下的Lua編程

寫在前面\\xLua是Unity3D下Lua編程解決方案&#xff0c;自2016年初推廣以來&#xff0c;已經應用于十多款騰訊自研游戲&#xff0c;因其良好性能、易用性、擴展性而廣受好評。現在&#xff0c;騰訊已經將xLua開源到GitHub。\\2016年12月末&#xff0c;xLua剛剛實現新的突破&…

設置安全性根據Folder關聯的條目模板設置上傳文檔安全性

文章結束給大家來個程序員笑話&#xff1a;[M] 在XT上可以設預條目模板&#xff08;EntryTemplate&#xff09;來到達模板化制控上傳文檔安全性和屬性等信息的作用。而EntryTemplate本身可以與Folder相干聯&#xff08;一個Folder可以關聯多個EntryTemplate&#xff09;&#x…

surfaceView中的線程問題

問題描述我在surfaceView中的surfaceCreated方法中start線程&#xff0c;但是當我start一個其他activity后&#xff0c;又finish掉那個acvitity回來&#xff0c;又會走到這個surfaceCreated方法&#xff0c;這時候走到線程的start方法&#xff0c;它會報錯Thread already exist…

1加6投屏_6月1日起駕考要加項目?真相是這樣

來源&#xff1a;新聞晨報近日網上流傳一則消息讓還沒考出駕照的朋友們瑟瑟發抖網傳消息稱&#xff0c;上海、海南、陜西、貴州、浙江等地駕考科目二于6月1日起加項&#xff0c;因而“朋友們要抓緊時間報名&#xff0c;錄入舊系統”。網傳消息截圖上海6月1日起科目二考試增加到…

Java this關鍵字

this 關鍵字有三個應用&#xff1a;  1.this調用本類中的屬性&#xff0c;也就是類中的成員變量  2.this調用本類中的其他方法  3.this調用本類中的其他構造方法&#xff0c;調用時要放在構造方法的首行 來看下面這段代碼&#xff1a; public String name;public void sh…

linux下查看線程數的幾種方法

1、 cat /proc/${pid}/status 2、pstree -p ${pid} 3、top -p ${pid} 再按H 或者直接輸入 top -bH -d 3 -p ${pid} top -H手冊中說&#xff1a;-H : Threads toggle加上這個選項啟動top&#xff0c;top一行顯示一個線程。否則&#xff0c;它一行顯示一個進程。 4、ps xH手冊…

網站等保測評針對服務器,互聯互通測評知識分享之信息安全建設要點

原創 醫療測評實驗室 中國軟件評測中心 1周前醫院互聯互通測評&#xff0c;即國家醫療健康信息互聯互通標準化成熟度測評&#xff0c;近年來隨著政策的要求、需求的驅動、技術的更迭、價值的引領&#xff0c;越來越被業內人士接受和認可&#xff0c;測評熱度也水漲船高。國家衛…

樹櫻花滿樹繁花

廢話就不多說了&#xff0c;開始。。。 學院的櫻花開了&#xff0c;花開的很盛&#xff0c;滿樹的繁花揚張著天春的力活。 武漢三月的時候櫻花就開了&#xff0c;武大的學同在空間里發各種玩游的照片&#xff0c;真是羨煞旁人。大連的天春來得晚&#xff0c;但究終還是趕上了。…

pandas合并groupby_pandas實踐之GroupBy()

官網地址&#xff1a;https://pandas.pydata.org/docs/reference/groupby.htmlpandas中對數據進行分組操作的方法&#xff0c;官方有很詳細的教程。下面的案例是真實遇到的問題&#xff0c;看一看用pandas是如何解決的。構造數據import pandas as pdimport numpy as npdf pd.D…

自學 web 前端人怎么找工作?

1&#xff0c;你做過的項目可以體現你的價值。2&#xff0c;你的個人博客可以反映你的思考。3&#xff0c;你的GitHub頁面可以展示你的項目。4&#xff0c;你項目中的代碼可以看出你編程的風格。1&#xff0c;2&#xff0c;3&#xff0c;4之間有交集。當你能證明&#xff0c;你…

《Breakfast At Tiffanys》

"生活中似乎有些男性想象著能拯救和引導一個年輕美麗純潔善良卻迷茫的女子&#xff0c;有些女性也想象著能用自己的善良與包容來安慰一個才華橫溢卻飽經苦悶與貧窮的男子&#xff0c;老實說&#xff0c;這很有成就感。雖然我的語氣有些諷刺&#xff0c;但我相信在這些“光…

項目不需要SVN控制的時候,該怎么辦

今天要用一個項目&#xff0c;當項目不需要SVN控制的時候&#xff0c;我們一般怎么辦哪&#xff1f;可能很多人設置Windows顯示隱藏文件&#xff0c;然后將項目中的所有.svn文件刪除。下面&#xff0c;從網上找了個非常簡單的方法第一步&#xff1a;建立一個名字叫做remove-svn…

erdas遙感圖像幾何校正_定量/高光譜遙感之—光譜分析技術

文章轉載自微信公眾號CSDN&#xff0c;作者冰清-小魔魚&#xff0c;版權歸原作者及刊載媒體所有。在定量遙感或者高光譜遙感中&#xff0c;信息提取主要用到光譜/波譜分析技術。本專題對光譜/波譜分析中涉及的流程及一些技術進行講解&#xff0c;包括以下內容&#xff1a;基本概…

Zipkin-1.19.0學習系列1:java范例

2019獨角獸企業重金招聘Python工程師標準>>> 官網地址: https://github.com/openzipkin/zipkin http://zipkin.io/ https://www.oschina.net/p/zipkin 截止到2017/1/4為止&#xff0c;最新版本為: Zipkin 1.19 下載地址: https://github.com/openzipkin/zipkin/arc…

PageRank算法

1. PageRank算法概述 PageRank,即網頁排名&#xff0c;又稱網頁級別、Google左側排名或佩奇排名。 是Google創始人拉里佩奇和謝爾蓋布林于1997年構建早期的搜索系統原型時提出的鏈接分析算法&#xff0c;自從Google在商業上獲得空前的成功后&#xff0c;該算法也成為其他搜索引…

linux中_在 Linux 桌面中開始使用 Lumina | Linux 中國

本文是 24 天 Linux 桌面特別系列的一部分。Lumina 桌面是讓你使用快速、合理的基于 Fluxbox 桌面的捷徑&#xff0c;它具有你無法缺少的所有功能。-- Seth Kenlon多年來&#xff0c;有一個名為 PC-BSD 的基于 FreeBSD 的桌面操作系統(OS)。它旨在作為一個常規使用的系統&#…