1 /*
2  * scamper_probe.h
3  *
4  * $Id: scamper_probe.h,v 1.47 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) 2012      Matthew Luckie
9  * Copyright (C) 2012-2015 The Regents of the University of California
10  * Copyright (C) 2020      Matthew Luckie
11  * Author: Matthew Luckie
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, version 2.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  *
26  */
27 
28 #ifndef __SCAMPER_PROBE_H
29 #define __SCAMPER_PROBE_H
30 
31 /*
32  * scamper_probe_ipopt
33  *
34  * this structure is used to hold IPv4 options and IPv6 extension headers.
35  */
36 typedef struct scamper_probe_ipopt
37 {
38   uint8_t type;
39 
40   union
41   {
42     struct v4tsps
43     {
44       struct in_addr   ips[4];
45       uint8_t          ipc;
46     } v4tsps;
47 
48     struct v6rh0
49     {
50       struct in6_addr *ips;
51       uint8_t          ipc;
52     } v6rh0;
53 
54     struct v6frag
55     {
56       uint16_t         off;
57       uint32_t         id;
58     } v6frag;
59 
60     struct quickstart
61     {
62       uint8_t          func;
63       uint8_t          rate;
64       uint8_t          ttl;
65       uint32_t         nonce;
66     } quickstart;
67   } un;
68 } scamper_probe_ipopt_t;
69 
70 #define opt_v4tsps_ips un.v4tsps.ips
71 #define opt_v4tsps_ipc un.v4tsps.ipc
72 #define opt_v6rh0_ips  un.v6rh0.ips
73 #define opt_v6rh0_ipc  un.v6rh0.ipc
74 #define opt_v6frag_off un.v6frag.off
75 #define opt_v6frag_id  un.v6frag.id
76 #define opt_qs_nonce   un.quickstart.nonce
77 #define opt_qs_ttl     un.quickstart.ttl
78 #define opt_qs_rate    un.quickstart.rate
79 #define opt_qs_func    un.quickstart.func
80 
81 #define SCAMPER_PROBE_IPOPTS_V6ROUTE0   0
82 #define SCAMPER_PROBE_IPOPTS_V6FRAG     1
83 #define SCAMPER_PROBE_IPOPTS_V4RR       2
84 #define SCAMPER_PROBE_IPOPTS_V4TSPS     3 /* TS: prespecified interfaces */
85 #define SCAMPER_PROBE_IPOPTS_V4TSO      4 /* TS: record only timestamps */
86 #define SCAMPER_PROBE_IPOPTS_V4TSAA     5 /* TS: record IP and timestamps */
87 #define SCAMPER_PROBE_IPOPTS_QUICKSTART 6 /* RFC 4782 */
88 
89 #define SCAMPER_PROBE_FLAG_IPID       0x0001
90 #define SCAMPER_PROBE_FLAG_NOFRAG     0x0002
91 #define SCAMPER_PROBE_FLAG_SPOOF      0x0004
92 #define SCAMPER_PROBE_FLAG_DL         0x0008
93 #define SCAMPER_PROBE_FLAG_RXERR      0x0010 /* socket is an rxerr variant */
94 
95 #define SCAMPER_PROBE_TCPOPT_SACK     0x01
96 #define SCAMPER_PROBE_TCPOPT_TS       0x02
97 #define SCAMPER_PROBE_TCPOPT_FO       0x04
98 #define SCAMPER_PROBE_TCPOPT_FO_EXP   0x08
99 
100 #define SCAMPER_PROBE_IS_IPID(pr) (                                      \
101   ((pr)->pr_flags & SCAMPER_PROBE_FLAG_IPID) != 0 &&                     \
102   (pr)->pr_ip_dst != NULL && SCAMPER_ADDR_TYPE_IS_IPV4((pr)->pr_ip_dst))
103 
104 /*
105  * scamper_probe
106  *
107  * this structure details how a probe should be formed and sent.
108  * it records any error code
109  */
110 typedef struct scamper_probe
111 {
112   /*
113    * the following fields define the socket to use.  note: they are optional
114    * (and ignored) if the scamper_probe_task function is called with a
115    * scamper_probe structure as it determines how to send the packet.
116    * if the caller requires the packet to be sent on a datalink socket, it
117    * must supply the datalink socket to use (in pr_dl) and a datalink header.
118    */
119   int                    pr_fd;
120   scamper_dl_t          *pr_dl;
121   uint8_t               *pr_dl_buf;
122   uint16_t               pr_dl_len;
123 
124   /* flags set on input */
125   uint16_t               pr_flags;
126 
127   /* IP address of router to send the packet to.  null means default router */
128   scamper_addr_t        *pr_rtr;
129 
130   /* IP header parameters */
131   scamper_addr_t        *pr_ip_src;
132   scamper_addr_t        *pr_ip_dst;
133   uint8_t                pr_ip_tos;
134   uint8_t                pr_ip_ttl;
135   uint8_t                pr_ip_proto;
136   uint16_t               pr_ip_id;        /* IPv4 ID */
137   uint16_t               pr_ip_off;
138   uint32_t               pr_ip_flow;      /* IPv6 flow id */
139 
140   /* IPv4 options / IPv6 extension headers */
141   scamper_probe_ipopt_t *pr_ipopts;
142   int                    pr_ipoptc;
143 
144   /* UDP header parameters */
145   uint16_t               pr_udp_sport;
146   uint16_t               pr_udp_dport;
147 
148   /* ICMP header parameters */
149   uint8_t                pr_icmp_type;
150   uint8_t                pr_icmp_code;
151   uint16_t               pr_icmp_sum;
152   uint16_t               pr_icmp_id;
153   uint16_t               pr_icmp_seq;
154   uint16_t               pr_icmp_mtu;
155 
156   /* TCP header parameters */
157   uint16_t               pr_tcp_sport;
158   uint16_t               pr_tcp_dport;
159   uint32_t               pr_tcp_seq;
160   uint32_t               pr_tcp_ack;
161   uint8_t                pr_tcp_flags;
162   uint8_t                pr_tcp_opts;
163   uint8_t                pr_tcp_wscale;
164   uint16_t               pr_tcp_win;
165   uint16_t               pr_tcp_mss;
166   uint32_t               pr_tcp_tsval;
167   uint32_t               pr_tcp_tsecr;
168   uint32_t               pr_tcp_sack[8];
169   uint8_t                pr_tcp_sackb;
170   uint8_t               *pr_tcp_fo_cookie;
171   uint8_t                pr_tcp_fo_cookielen;
172 
173   /* the contents of the packet's body */
174   uint8_t               *pr_data;
175   uint16_t               pr_len;
176 
177   /* the time immediately before the call to sendto was made */
178   struct timeval         pr_tx;
179 
180   /* the actual transmitted packet, IP header and down, when datalink tx'd */
181   uint8_t               *pr_tx_raw;
182   uint16_t               pr_tx_rawlen;
183 
184   /* if an error occurs in the probe function, the errno is recorded */
185   int                    pr_errno;
186 } scamper_probe_t;
187 
188 int scamper_probe(scamper_probe_t *probe);
189 
190 #ifdef __SCAMPER_TASK_H
191 int scamper_probe_task(scamper_probe_t *probe, scamper_task_t *task);
192 #endif
193 
194 /* convenience macro to construct an ICMP echo packet */
195 #define SCAMPER_PROBE_ICMP_ECHO(pr, id, seq) do {		\
196   assert((pr)->pr_ip_dst != NULL);				\
197   assert((pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4 ||	\
198 	 (pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV6);	\
199   if((pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4)		\
200     {								\
201       (pr)->pr_ip_proto  = IPPROTO_ICMP;			\
202       (pr)->pr_icmp_type = ICMP_ECHO;				\
203     }								\
204   else								\
205     {								\
206       (pr)->pr_ip_proto  = IPPROTO_ICMPV6;			\
207       (pr)->pr_icmp_type = ICMP6_ECHO_REQUEST;			\
208     }								\
209   (pr)->pr_icmp_id = (id);					\
210   (pr)->pr_icmp_seq = (seq);					\
211   } while(0)
212 
213 /* convenience macro to construct an ICMP timestamp request packet */
214 #define SCAMPER_PROBE_ICMP_TIME(pr, id, seq) do {		\
215   assert((pr)->pr_ip_dst != NULL);				\
216   assert((pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4);	\
217   (pr)->pr_ip_proto = IPPROTO_ICMP;				\
218   (pr)->pr_icmp_type = ICMP_TSTAMP;				\
219   (pr)->pr_icmp_id = (id);					\
220   (pr)->pr_icmp_seq = (seq);					\
221   } while(0)
222 
223 #define SCAMPER_PROBE_ICMP_PTB(pr, mtu) do {			\
224   assert((pr)->pr_ip_dst != NULL);				\
225   assert((pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4 ||	\
226 	 (pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV6);	\
227   if((pr)->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4)		\
228     {								\
229       (pr)->pr_ip_proto  = IPPROTO_ICMP;			\
230       (pr)->pr_icmp_type = ICMP_UNREACH;			\
231       (pr)->pr_icmp_code = ICMP_UNREACH_NEEDFRAG;		\
232     }								\
233   else								\
234     {								\
235       (pr)->pr_ip_proto  = IPPROTO_ICMPV6;			\
236       (pr)->pr_icmp_type = ICMP6_PACKET_TOO_BIG;		\
237     }								\
238   (pr)->pr_icmp_mtu = (mtu);					\
239   } while(0)
240 
241 /*
242  * scamper_probe_cleanup:
243  * cleanup any state kept inside the scamper_probe module
244  */
245 int scamper_probe_init(void);
246 void scamper_probe_cleanup(void);
247 
248 #endif /* __SCAMPER_PROBE_H */
249