1 /*
2  * scamper_icmp_resp.h
3  *
4  * $Id: scamper_icmp_resp.h,v 1.34 2020/06/12 23:29:25 mjl Exp $
5  *
6  * Copyright (C) 2005-2006 Matthew Luckie
7  * Copyright (C) 2006-2011 The University of Waikato
8  * Copyright (C) 2013      The Regents of the University of California
9  * Copyright (C) 2020      Matthew Luckie
10  * Author: Matthew Luckie
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  */
26 
27 #ifndef __SCAMPER_ICMP_RESP_H
28 #define __SCAMPER_ICMP_RESP_H
29 
30 #define SCAMPER_ICMP_RESP_FLAG_KERNRX          0x01
31 #define SCAMPER_ICMP_RESP_FLAG_INNER_IP        0x02
32 #define SCAMPER_ICMP_RESP_FLAG_IPOPT_TS        0x04
33 #define SCAMPER_ICMP_RESP_FLAG_INNER_IPOPT_TS  0x08
34 #define SCAMPER_ICMP_RESP_FLAG_RXERR           0x10
35 
36 #define SCAMPER_ICMP_RESP_IS_ECHO_REPLY(ir) ( \
37  (ir->ir_af == AF_INET  && ir->ir_icmp_type == 0) || \
38  (ir->ir_af == AF_INET6 && ir->ir_icmp_type == 129))
39 
40 #define SCAMPER_ICMP_RESP_IS_TIME_REPLY(ir) ( \
41  (ir->ir_af == AF_INET && ir->ir_icmp_type == 14))
42 
43 #define SCAMPER_ICMP_RESP_IS_TTL_EXP(ir) ( \
44  (ir->ir_af == AF_INET  && ir->ir_icmp_type == 11) || \
45  (ir->ir_af == AF_INET6 && ir->ir_icmp_type == 3))
46 
47 #define SCAMPER_ICMP_RESP_IS_UNREACH(ir) ( \
48  (ir->ir_af == AF_INET  && ir->ir_icmp_type == 3) || \
49  (ir->ir_af == AF_INET6 && ir->ir_icmp_type == 1))
50 
51 #define SCAMPER_ICMP_RESP_IS_UNREACH_PORT(ir) ( \
52  (ir->ir_af == AF_INET && ir->ir_icmp_type == 3 && ir->ir_icmp_code == 3) || \
53  (ir->ir_af == AF_INET6 && ir->ir_icmp_type == 1 && ir->ir_icmp_code == 4))
54 
55 #define SCAMPER_ICMP_RESP_IS_PACKET_TOO_BIG(ir) ( \
56  (ir->ir_af == AF_INET && ir->ir_icmp_type == 3 && ir->ir_icmp_code == 4) || \
57  (ir->ir_af == AF_INET6 && ir->ir_icmp_type == 2))
58 
59 #define SCAMPER_ICMP_RESP_IS_PARAMPROB(ir) ( \
60  (ir->ir_af == AF_INET && ir->ir_icmp_type == 12))
61 
62 /* this macro checks to see if the inner structs are valid */
63 #define SCAMPER_ICMP_RESP_INNER_IS_SET(ir) ( \
64  ((ir->ir_flags & SCAMPER_ICMP_RESP_FLAG_INNER_IP) != 0))
65 
66 #define SCAMPER_ICMP_RESP_INNER_IS_ICMP(ir) ( \
67  (ir->ir_af == AF_INET  && ir->ir_inner_ip_proto == 1) || \
68  (ir->ir_af == AF_INET6 && ir->ir_inner_ip_proto == 58))
69 
70 #define SCAMPER_ICMP_RESP_INNER_IS_TCP(ir) ( \
71  (ir->ir_inner_ip_proto == 6))
72 
73 #define SCAMPER_ICMP_RESP_INNER_IS_UDP(ir) ( \
74  (ir->ir_inner_ip_proto == 17))
75 
76 #define SCAMPER_ICMP_RESP_INNER_IS_ICMP_ECHO_REQ(ir) ( \
77  (ir->ir_af == AF_INET  && \
78   ir->ir_inner_ip_proto == 1  && ir->ir_inner_icmp_type == 8) || \
79  (ir->ir_af == AF_INET6 && \
80   ir->ir_inner_ip_proto == 58 && ir->ir_inner_icmp_type == 128))
81 
82 #define SCAMPER_ICMP_RESP_INNER_IS_ICMP_TIME_REQ(ir) (	\
83  ir->ir_af == AF_INET && \
84  ir->ir_inner_ip_proto == 1 && ir->ir_inner_icmp_type == 13)
85 
86 /*
87  * an ICMP response may consist of up to four pieces.  when an ICMP
88  * packet is received, scamper parses the packet and records values of
89  * interest in this structure.
90  *
91  * the four pieces of interesting information can be broken up into the
92  * following categories:
93  *
94  * 1. the IP header
95  * 2. the ICMP header
96  * 3. [optional] IP header of probe that caused this message
97  * 4. [optional] transport header of probe that caused this message
98  *
99  * the optional pieces - the 'inner' IP and transport headers are found
100  * depending on the type / code of the ICMP message.  they are always
101  * found in 'destination unreachable' type messages, but obviously
102  * are not found in echo replies or the like.
103  */
104 typedef struct scamper_icmp_resp
105 {
106   /* the address family (AF_INET / AF_INET6) of the response */
107   int               ir_af;
108 
109   /* the icmp file descriptor the message was received on */
110   int               ir_fd;
111 
112   /* when the ICMP response was received */
113   struct timeval    ir_rx;
114 
115   /* flags, whose meanings are defined above */
116   uint8_t           ir_flags;
117 
118   /*
119    * category 1: the IP header;
120    *
121    * scamper records the source of the ICMP message but not the destination,
122    * as that is the host scamper is running on, and that is not interesting.
123    *
124    * scamper also records the size, ttl, ipid, and tos fields of the
125    * response
126    */
127   union
128   {
129     struct in_addr  v4;
130     struct in6_addr v6;
131   } ir_ip_src;
132 
133   uint16_t          ir_ip_size;
134   uint16_t          ir_ip_id;
135   uint8_t           ir_ip_tos;
136   int16_t           ir_ip_ttl;  /* ir_ip_hlim; -1 if unavailable */
137 
138   /*
139    * if the response includes the IPv4 record route option, IP addresses
140    * are found here.
141    */
142   struct in_addr   *ir_ipopt_rrs;
143   uint8_t           ir_ipopt_rrc;
144 
145   /*
146    * if the response includes the IPv4 timestamp option, the results of it
147    * are found in here.
148    */
149   uint8_t           ir_ipopt_tsc;
150   struct in_addr   *ir_ipopt_tsips;
151   uint32_t         *ir_ipopt_tstss;
152 
153   /*
154    * category 2: the ICMP header;
155    *
156    * scamper records the type and code of the ICMP message.  depending on
157    * the type of the message, optional ICMP id and sequence fields are
158    * also recorded.  if the message
159    */
160   uint8_t           ir_icmp_type;
161   uint8_t           ir_icmp_code;
162   uint16_t          ir_icmp_id;
163   uint16_t          ir_icmp_seq;
164   uint16_t          ir_icmp_nhmtu;
165   uint8_t           ir_icmp_pptr;
166   uint32_t          ir_icmp_tso;
167   uint32_t          ir_icmp_tsr;
168   uint32_t          ir_icmp_tst;
169 
170   /*
171    * category 3: the inner IP header;
172    *
173    * if the ICMP type/code hints that a portion of the probe is included
174    * in the ICMP response, then scamper records interesting portions of the
175    * IP header.  we don't record the source address, as that is the host
176    * that scamper is running on, and that does not seem to be interesting.
177    */
178   union
179   {
180     struct in_addr  v4;
181     struct in6_addr v6;
182   } ir_inner_ip_dst;
183 
184   uint16_t          ir_inner_ip_size;
185   uint32_t          ir_inner_ip_id;    /* fragment id */
186   uint16_t          ir_inner_ip_off;   /* fragment offset, no bits */
187   uint32_t          ir_inner_ip_flow;  /* IPv6 flow */
188   uint8_t           ir_inner_ip_tos;
189   uint8_t           ir_inner_ip_ttl;   /* ir_inner_ip_hlim */
190   uint8_t           ir_inner_ip_proto;
191   struct in_addr   *ir_inner_ipopt_rrs;
192   uint8_t           ir_inner_ipopt_rrc;
193   uint8_t           ir_inner_ipopt_tsc;
194   struct in_addr   *ir_inner_ipopt_tsips;
195   uint32_t         *ir_inner_ipopt_tstss;
196 
197   uint8_t          *ir_inner_data;
198   uint16_t          ir_inner_datalen;
199 
200   /*
201    * category 4: details of the transport header
202    *
203    * the IPv4 ICMP RFC says that if an ICMP error message
204    */
205   union
206   {
207     struct irt_udp
208     {
209       uint16_t  sport;
210       uint16_t  dport;
211       uint16_t  sum;
212       uint8_t  *data;
213       uint16_t  datalen;
214     } irit_udp;
215 
216     struct irt_tcp
217     {
218       uint16_t sport;
219       uint16_t dport;
220       uint32_t seq;
221     } irit_tcp;
222 
223     struct irt_icmp
224     {
225       uint8_t  type;
226       uint8_t  code;
227       uint16_t sum;
228       uint16_t id;
229       uint16_t seq;
230     } irit_icmp;
231   } ir_inner_trans_un;
232 
233   uint8_t          *ir_ext;
234   uint16_t          ir_extlen;
235 
236 } scamper_icmp_resp_t;
237 
238 #define ir_ip_hlim         ir_ip_ttl
239 
240 #define ir_inner_ip_hlim     ir_inner_ip_ttl
241 #define ir_inner_udp_sport   ir_inner_trans_un.irit_udp.sport
242 #define ir_inner_udp_dport   ir_inner_trans_un.irit_udp.dport
243 #define ir_inner_udp_sum     ir_inner_trans_un.irit_udp.sum
244 #define ir_inner_udp_data    ir_inner_trans_un.irit_udp.data
245 #define ir_inner_udp_datalen ir_inner_trans_un.irit_udp.datalen
246 #define ir_inner_tcp_sport   ir_inner_trans_un.irit_tcp.sport
247 #define ir_inner_tcp_dport   ir_inner_trans_un.irit_tcp.dport
248 #define ir_inner_tcp_seq     ir_inner_trans_un.irit_tcp.seq
249 #define ir_inner_icmp_type   ir_inner_trans_un.irit_icmp.type
250 #define ir_inner_icmp_code   ir_inner_trans_un.irit_icmp.code
251 #define ir_inner_icmp_sum    ir_inner_trans_un.irit_icmp.sum
252 #define ir_inner_icmp_id     ir_inner_trans_un.irit_icmp.id
253 #define ir_inner_icmp_seq    ir_inner_trans_un.irit_icmp.seq
254 
255 int scamper_icmp_resp_src(scamper_icmp_resp_t *resp, scamper_addr_t *addr);
256 int scamper_icmp_resp_inner_dst(scamper_icmp_resp_t *resp, scamper_addr_t *a);
257 
258 void scamper_icmp_resp_handle(scamper_icmp_resp_t *resp);
259 
260 void scamper_icmp_resp_clean(scamper_icmp_resp_t *ir);
261 
262 /* scamper only uses this function if it is built in debug mode */
263 #if !defined(NDEBUG) || !defined(WITHOUT_DEBUGFILE)
264 void    scamper_icmp_resp_print(const scamper_icmp_resp_t *resp);
265 #else
266 #define scamper_icmp_resp_print(resp) ((void)0)
267 #endif
268 
269 #endif /* __SCAMPER_ICMP_RESP_H */
270