1 /*
2 * scamper_ip4.c
3 *
4 * $Id: scamper_ip4.c,v 1.18 2020/03/17 07:32:16 mjl Exp $
5 *
6 * Copyright (C) 2009-2011 The University of Waikato
7 * Author: Matthew Luckie
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, version 2.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include "internal.h"
28
29 #include "scamper_addr.h"
30 #include "scamper_dl.h"
31 #include "scamper_probe.h"
32 #include "scamper_ip4.h"
33 #include "scamper_tcp4.h"
34 #include "scamper_privsep.h"
35 #include "scamper_debug.h"
36 #include "utils.h"
37
scamper_ip4_close(int fd)38 void scamper_ip4_close(int fd)
39 {
40 #ifndef _WIN32
41 close(fd);
42 #else
43 closesocket(fd);
44 #endif
45 return;
46 }
47
scamper_ip4_openraw_fd(void)48 int scamper_ip4_openraw_fd(void)
49 {
50 int fd, hdr;
51 if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
52 {
53 printerror(__func__, "could not open socket");
54 goto err;
55 }
56 hdr = 1;
57 if(setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (void *)&hdr, sizeof(hdr)) == -1)
58 {
59 printerror(__func__, "could not IP_HDRINCL");
60 goto err;
61 }
62 return fd;
63
64 err:
65 if(fd != -1) scamper_ip4_close(fd);
66 return -1;
67 }
68
scamper_ip4_openraw(void)69 int scamper_ip4_openraw(void)
70 {
71 #if defined(WITHOUT_PRIVSEP)
72 return scamper_ip4_openraw_fd();
73 #else
74 return scamper_privsep_open_rawip();
75 #endif
76 }
77
scamper_ip4_hlen(scamper_probe_t * pr,size_t * hlen)78 int scamper_ip4_hlen(scamper_probe_t *pr, size_t *hlen)
79 {
80 size_t ip4hlen = sizeof(struct ip);
81 scamper_probe_ipopt_t *opt;
82 int i;
83
84 for(i=0; i<pr->pr_ipoptc; i++)
85 {
86 opt = &pr->pr_ipopts[i];
87 if(opt->type == SCAMPER_PROBE_IPOPTS_V4RR)
88 {
89 /*
90 * want the ability to record at least one IP address otherwise
91 * the option is useless.
92 */
93 if(ip4hlen + 8 > 60)
94 goto err;
95
96 /* for now assume this option fills the rest of the option space */
97 ip4hlen = 60;
98 }
99 else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS)
100 {
101 if(opt->opt_v4tsps_ipc < 1 || opt->opt_v4tsps_ipc > 4)
102 goto err;
103
104 ip4hlen += (opt->opt_v4tsps_ipc * 4 * 2) + 4;
105 if(ip4hlen > 60)
106 goto err;
107 }
108 else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSO)
109 {
110 ip4hlen += 40;
111 if(ip4hlen > 60)
112 goto err;
113 }
114 else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA)
115 {
116 ip4hlen += 36;
117 if(ip4hlen > 60)
118 goto err;
119 }
120 else if(opt->type == SCAMPER_PROBE_IPOPTS_QUICKSTART)
121 {
122 ip4hlen += 8;
123 if(ip4hlen > 60)
124 goto err;
125 }
126 else goto err;
127 }
128
129 *hlen = ip4hlen;
130 return 0;
131
132 err:
133 scamper_debug(__func__, "invalid IPv4 header specification");
134 return -1;
135 }
136
scamper_ip4_build(scamper_probe_t * pr,uint8_t * buf,size_t * len)137 int scamper_ip4_build(scamper_probe_t *pr, uint8_t *buf, size_t *len)
138 {
139 scamper_probe_ipopt_t *opt;
140 struct ip *ip;
141 size_t off, ip4hlen;
142 int i, j;
143
144 if(scamper_ip4_hlen(pr, &ip4hlen) != 0)
145 return -1;
146
147 if(ip4hlen > *len)
148 {
149 *len = ip4hlen;
150 return -1;
151 }
152
153 ip = (struct ip *)buf;
154 off = sizeof(struct ip);
155
156 #ifndef _WIN32
157 ip->ip_v = 4;
158 ip->ip_hl = (ip4hlen / 4);
159 #else
160 ip->ip_vhl = 0x40 | (ip4hlen / 4);
161 #endif
162
163 if((pr->pr_ip_off & IP_OFFMASK) != 0)
164 ip->ip_len = htons(ip4hlen + pr->pr_len);
165 else if(pr->pr_ip_proto == IPPROTO_ICMP || pr->pr_ip_proto == IPPROTO_UDP)
166 ip->ip_len = htons(ip4hlen + 8 + pr->pr_len);
167 else if(pr->pr_ip_proto == IPPROTO_TCP)
168 ip->ip_len = htons(ip4hlen + scamper_tcp4_hlen(pr) + pr->pr_len);
169 else
170 {
171 scamper_debug(__func__, "unimplemented pr %d", pr->pr_ip_proto);
172 return -1;
173 }
174
175 ip->ip_tos = pr->pr_ip_tos;
176 ip->ip_id = htons(pr->pr_ip_id);
177 ip->ip_off = htons(pr->pr_ip_off);
178 ip->ip_ttl = pr->pr_ip_ttl;
179 ip->ip_p = pr->pr_ip_proto;
180 ip->ip_sum = 0;
181 memcpy(&ip->ip_src, pr->pr_ip_src->addr, sizeof(ip->ip_src));
182 memcpy(&ip->ip_dst, pr->pr_ip_dst->addr, sizeof(ip->ip_dst));
183
184 for(i=0; i<pr->pr_ipoptc; i++)
185 {
186 opt = &pr->pr_ipopts[i];
187 if(opt->type == SCAMPER_PROBE_IPOPTS_V4RR)
188 {
189 memset(buf+off+3, 0, 37);
190 buf[off+0] = 7;
191 buf[off+1] = 39;
192 buf[off+2] = 4;
193 off = 60;
194 }
195 else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS ||
196 opt->type == SCAMPER_PROBE_IPOPTS_V4TSO ||
197 opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA)
198 {
199 buf[off+0] = 68;
200 buf[off+2] = 5;
201
202 if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS)
203 {
204 buf[off+1] = (opt->opt_v4tsps_ipc * 4 * 2) + 4;
205 buf[off+3] = 3;
206 off += 4;
207 for(j=0; j<opt->opt_v4tsps_ipc; j++)
208 {
209 memcpy(buf+off, &opt->opt_v4tsps_ips[j], 4); off += 4;
210 memset(buf+off, 0, 4); off += 4;
211 }
212 }
213 else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSO)
214 {
215 buf[off+1] = 40;
216 memset(buf+off+3, 0, 41);
217 off += 40;
218 }
219 else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA)
220 {
221 buf[off+1] = 36;
222 buf[off+3] = 1;
223 memset(buf+off+4, 0, 36);
224 off += 36;
225 }
226 }
227 else if(opt->type == SCAMPER_PROBE_IPOPTS_QUICKSTART)
228 {
229 assert(opt->opt_qs_func <= 0xf);
230 assert(opt->opt_qs_rate <= 0xf);
231 buf[off+0] = 25;
232 buf[off+1] = 8;
233 buf[off+2] = (opt->opt_qs_func << 4) | opt->opt_qs_rate;
234 buf[off+3] = opt->opt_qs_ttl;
235 bytes_htonl(&buf[off+4], opt->opt_qs_nonce << 2);
236 off += 8;
237 }
238 else return -1;
239 }
240
241 assert(off == ip4hlen);
242 ip->ip_sum = in_cksum(ip, ip4hlen);
243
244 *len = off;
245 return 0;
246 }
247
248 /*
249 * scamper_ip4_frag_build
250 *
251 * given an IPv4 fragment, build it.
252 */
scamper_ip4_frag_build(scamper_probe_t * probe,uint8_t * buf,size_t * len)253 int scamper_ip4_frag_build(scamper_probe_t *probe, uint8_t *buf, size_t *len)
254 {
255 size_t ip4hlen, req;
256 int rc = 0;
257
258 /* build the IPv4 header */
259 ip4hlen = *len;
260 scamper_ip4_build(probe, buf, &ip4hlen);
261
262 /* calculate the total number of bytes required for this packet */
263 req = ip4hlen + probe->pr_len;
264
265 if(req > *len)
266 rc = -1;
267 else if(probe->pr_len != 0)
268 memcpy(buf + ip4hlen, probe->pr_data, probe->pr_len);
269
270 *len = req;
271 return rc;
272 }
273