Ticket #4529: program.cpp

File program.cpp, 6.8 KB (added by webmaster@…, 12 years ago)

Program with a simple traceroute demonstrating the failed setting of TTL.

Line 
1#include <iostream>
2#include <sstream>
3#include <stdexcept>
4#include <vector>
5#include <boost/asio.hpp>
6#include "icmp_header.hpp" // from boost::asio examples on boost website
7 // (also pasted last in this file)
8
9using boost::asio::ip::icmp;
10
11class traceroute: public boost::noncopyable
12{
13 public:
14 traceroute(const char* host):
15 io(),
16 resolver(io),
17 socket(io, icmp::v4()),
18 sequence_number(0)
19 {
20 icmp::resolver::query query(icmp::v4(), host, "");
21 destination = *resolver.resolve(query);
22 }
23 ~traceroute() { socket.close(); }
24 void trace()
25 {
26 for( int ttl(1); ttl < 31 ; ttl++)
27 {
28 const boost::asio::ip::unicast::hops option( ttl );
29 socket.set_option(option);
30
31 boost::asio::ip::unicast::hops op;
32 socket.get_option(op);
33 if( ttl != op.value() )
34 {
35 std::ostringstream o;
36 o << "TTL not set properly. Should be "
37 << ttl << " but was set to "
38 << op.value() << '.';
39 throw std::runtime_error(o.str());
40 }
41
42 // Create an ICMP header for an echo request.
43 icmp_header echo_request;
44 echo_request.type(icmp_header::echo_request);
45 echo_request.code(0);
46 echo_request.identifier(get_identifier());
47 echo_request.sequence_number(++sequence_number);
48 const std::string body("");
49 compute_checksum(echo_request, body.begin(), body.end());
50
51 // Encode the request packet.
52 boost::asio::streambuf request_buffer;
53 std::ostream os(&request_buffer);
54 os << echo_request << body;
55
56 // Send the request.
57 socket.send_to(request_buffer.data(), destination);
58
59 // Recieve some data and parse it.
60 std::vector<boost::uint8_t> data(64,0);
61 const std::size_t nr(
62 socket.receive(
63 boost::asio::buffer(data) ) );
64 if( nr < 16 )
65 {
66 throw std::runtime_error("To few bytes returned.");
67 }
68 std::ostringstream remote_ip;
69 remote_ip
70 << (int)data[12] << '.'
71 << (int)data[13] << '.'
72 << (int)data[14] << '.'
73 << (int)data[15];
74 std::cout << remote_ip.str() << '\n';
75 if( boost::asio::ip::address_v4::from_string( remote_ip.str() )
76 == destination.address() )
77 {
78 break;
79 }
80 }
81 }
82 private:
83 static const int port = 33434;
84 boost::asio::io_service io;
85 boost::asio::ip::icmp::resolver resolver;
86 boost::asio::ip::icmp::socket socket ;
87 unsigned short sequence_number;
88 boost::asio::ip::icmp::endpoint destination;
89 static unsigned short get_identifier()
90 {
91#if defined(BOOST_WINDOWS)
92 return static_cast<unsigned short>(::GetCurrentProcessId());
93#else
94 return static_cast<unsigned short>(::getpid());
95#endif
96 }
97};
98
99int main( int argc, char** argv)
100{
101 try
102 {
103 if( argc != 2 )
104 {
105 throw std::invalid_argument("Usage: traceroute host");
106 }
107 traceroute T( argv[1] );
108 T.trace();
109 }
110 catch( const std::exception& e )
111 {
112 std::cerr << e.what() << '\n';
113 }
114}
115
116
117
118
119
120
121//
122// icmp_header.hpp
123// ~~~~~~~~~~~~~~~
124//
125// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
126//
127// Distributed under the Boost Software License, Version 1.0. (See accompanying
128// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
129//
130
131#ifndef ICMP_HEADER_HPP
132#define ICMP_HEADER_HPP
133
134#include <istream>
135#include <ostream>
136#include <algorithm>
137
138// ICMP header for both IPv4 and IPv6.
139//
140// The wire format of an ICMP header is:
141//
142// 0 8 16 31
143// +---------------+---------------+------------------------------+ ---
144// | | | | ^
145// | type | code | checksum | |
146// | | | | |
147// +---------------+---------------+------------------------------+ 8 bytes
148// | | | |
149// | identifier | sequence number | |
150// | | | v
151// +-------------------------------+------------------------------+ ---
152
153class icmp_header
154{
155public:
156 enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,
157 redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,
158 timestamp_request = 13, timestamp_reply = 14, info_request = 15,
159 info_reply = 16, address_request = 17, address_reply = 18 };
160
161 icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
162
163 unsigned char type() const { return rep_[0]; }
164 unsigned char code() const { return rep_[1]; }
165 unsigned short checksum() const { return decode(2, 3); }
166 unsigned short identifier() const { return decode(4, 5); }
167 unsigned short sequence_number() const { return decode(6, 7); }
168
169 void type(unsigned char n) { rep_[0] = n; }
170 void code(unsigned char n) { rep_[1] = n; }
171 void checksum(unsigned short n) { encode(2, 3, n); }
172 void identifier(unsigned short n) { encode(4, 5, n); }
173 void sequence_number(unsigned short n) { encode(6, 7, n); }
174
175 friend std::istream& operator>>(std::istream& is, icmp_header& header)
176 { return is.read(reinterpret_cast<char*>(header.rep_), 8); }
177
178 friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
179 { return os.write(reinterpret_cast<const char*>(header.rep_), 8); }
180
181private:
182 unsigned short decode(int a, int b) const
183 { return (rep_[a] << 8) + rep_[b]; }
184
185 void encode(int a, int b, unsigned short n)
186 {
187 rep_[a] = static_cast<unsigned char>(n >> 8);
188 rep_[b] = static_cast<unsigned char>(n & 0xFF);
189 }
190
191 unsigned char rep_[8];
192};
193
194template <typename Iterator>
195void compute_checksum(icmp_header& header,
196 Iterator body_begin, Iterator body_end)
197{
198 unsigned int sum = (header.type() << 8) + header.code()
199 + header.identifier() + header.sequence_number();
200
201 Iterator body_iter = body_begin;
202 while (body_iter != body_end)
203 {
204 sum += (static_cast<unsigned char>(*body_iter++) << 8);
205 if (body_iter != body_end)
206 sum += static_cast<unsigned char>(*body_iter++);
207 }
208
209 sum = (sum >> 16) + (sum & 0xFFFF);
210 sum += (sum >> 16);
211 header.checksum(static_cast<unsigned short>(~sum));
212}
213
214#endif // ICMP_HEADER_HPP
215