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