1 /*
2 * scamper_udp4.c
3 *
4 * $Id: scamper_udp4.c,v 1.75 2020/03/17 07:32:16 mjl Exp $
5 *
6 * Copyright (C) 2003-2006 Matthew Luckie
7 * Copyright (C) 2006-2010 The University of Waikato
8 * Author: Matthew Luckie
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, version 2.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include "internal.h"
29
30 #include "scamper_addr.h"
31 #include "scamper_dl.h"
32 #include "scamper_probe.h"
33 #include "scamper_ip4.h"
34 #include "scamper_udp4.h"
35 #include "scamper_privsep.h"
36 #include "scamper_debug.h"
37 #include "utils.h"
38
39 /*
40 * these variables are used to store a packet buffer that is allocated
41 * in the scamper_udp4_probe function large enough for the largest probe
42 * the routine sends
43 */
44 static uint8_t *pktbuf = NULL;
45 static size_t pktbuf_len = 0;
46
scamper_udp4_cksum(scamper_probe_t * probe)47 uint16_t scamper_udp4_cksum(scamper_probe_t *probe)
48 {
49 uint16_t tmp, *w;
50 int i, sum = 0;
51
52 /* compute the checksum over the psuedo header */
53 w = (uint16_t *)probe->pr_ip_src->addr;
54 sum += *w++; sum += *w++;
55 w = (uint16_t *)probe->pr_ip_dst->addr;
56 sum += *w++; sum += *w++;
57 sum += htons(IPPROTO_UDP);
58 sum += htons(probe->pr_len + 8);
59
60 /* main UDP header */
61 sum += htons(probe->pr_udp_sport);
62 sum += htons(probe->pr_udp_dport);
63 sum += htons(probe->pr_len + 8);
64
65 /* compute the checksum over the payload of the UDP message */
66 w = (uint16_t *)probe->pr_data;
67 for(i = probe->pr_len; i > 1; i -= 2)
68 {
69 sum += *w++;
70 }
71 if(i != 0)
72 {
73 sum += ((uint8_t *)w)[0];
74 }
75
76 /* fold the checksum */
77 sum = (sum >> 16) + (sum & 0xffff);
78 sum += (sum >> 16);
79
80 if((tmp = ~sum) == 0)
81 {
82 tmp = 0xffff;
83 }
84
85 return tmp;
86 }
87
udp4_build(scamper_probe_t * probe,uint8_t * buf)88 static void udp4_build(scamper_probe_t *probe, uint8_t *buf)
89 {
90 struct udphdr *udp = (struct udphdr *)buf;
91
92 udp->uh_sport = htons(probe->pr_udp_sport);
93 udp->uh_dport = htons(probe->pr_udp_dport);
94 udp->uh_ulen = htons(8 + probe->pr_len);
95 udp->uh_sum = scamper_udp4_cksum(probe);
96
97 /* if there is data to include in the payload, copy it in now */
98 if(probe->pr_len > 0)
99 {
100 memcpy(buf + 8, probe->pr_data, probe->pr_len);
101 }
102
103 return;
104 }
105
scamper_udp4_build(scamper_probe_t * probe,uint8_t * buf,size_t * len)106 int scamper_udp4_build(scamper_probe_t *probe, uint8_t *buf, size_t *len)
107 {
108 size_t ip4hlen, req;
109 int rc = 0;
110
111 ip4hlen = *len;
112 scamper_ip4_build(probe, buf, &ip4hlen);
113 req = ip4hlen + 8 + probe->pr_len;
114
115 if(req <= *len)
116 udp4_build(probe, buf + ip4hlen);
117 else
118 rc = -1;
119
120 *len = req;
121 return rc;
122 }
123
scamper_udp4_probe(scamper_probe_t * probe)124 int scamper_udp4_probe(scamper_probe_t *probe)
125 {
126 struct sockaddr_in sin4;
127 int i;
128 char addr[128];
129 size_t ip4hlen, len, tmp;
130 uint8_t *buf;
131
132 #if !defined(IP_HDR_HTONS)
133 struct ip *ip;
134 #endif
135
136 assert(probe != NULL);
137 assert(probe->pr_ip_proto == IPPROTO_UDP);
138 assert(probe->pr_ip_dst != NULL);
139 assert(probe->pr_ip_src != NULL);
140 assert(probe->pr_len > 0 || probe->pr_data == NULL);
141
142 scamper_ip4_hlen(probe, &ip4hlen);
143
144 /* compute length, for sake of readability */
145 len = ip4hlen + sizeof(struct udphdr) + probe->pr_len;
146
147 if(pktbuf_len < len)
148 {
149 if((buf = realloc(pktbuf, len)) == NULL)
150 {
151 printerror(__func__, "could not realloc");
152 return -1;
153 }
154 pktbuf = buf;
155 pktbuf_len = len;
156 }
157
158 tmp = len;
159 scamper_ip4_build(probe, pktbuf, &tmp);
160
161 #if !defined(IP_HDR_HTONS)
162 ip = (struct ip *)pktbuf;
163 ip->ip_len = ntohs(ip->ip_len);
164 ip->ip_off = ntohs(ip->ip_off);
165 #endif
166
167 udp4_build(probe, pktbuf + ip4hlen);
168
169 sockaddr_compose((struct sockaddr *)&sin4, AF_INET,
170 probe->pr_ip_dst->addr, probe->pr_udp_dport);
171
172 /* get the transmit time immediately before we send the packet */
173 gettimeofday_wrap(&probe->pr_tx);
174
175 i = sendto(probe->pr_fd, pktbuf, len, 0, (struct sockaddr *)&sin4,
176 sizeof(struct sockaddr_in));
177
178 if(i < 0)
179 {
180 /* error condition, could not send the packet at all */
181 probe->pr_errno = errno;
182 printerror(__func__, "could not send to %s (%d ttl, %d dport, %d len)",
183 scamper_addr_tostr(probe->pr_ip_dst, addr, sizeof(addr)),
184 probe->pr_ip_ttl, probe->pr_udp_dport, len);
185 return -1;
186 }
187 else if((size_t)i != len)
188 {
189 /* error condition, sent a portion of the probe */
190 printerror_msg(__func__, "sent %d bytes of %d byte packet to %s",
191 i, (int)len,
192 scamper_addr_tostr(probe->pr_ip_dst, addr, sizeof(addr)));
193 return -1;
194 }
195
196 return 0;
197 }
198
scamper_udp4_cleanup()199 void scamper_udp4_cleanup()
200 {
201 if(pktbuf != NULL)
202 {
203 free(pktbuf);
204 pktbuf = NULL;
205 }
206
207 return;
208 }
209
scamper_udp4_close(int fd)210 void scamper_udp4_close(int fd)
211 {
212 #ifndef _WIN32
213 close(fd);
214 #else
215 closesocket(fd);
216 #endif
217 return;
218 }
219
scamper_udp4_opendgram(const void * addr,int sport)220 int scamper_udp4_opendgram(const void *addr, int sport)
221 {
222 struct sockaddr_in sin4;
223 char tmp[32];
224 int fd, opt;
225
226 if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
227 {
228 printerror(__func__, "could not open socket");
229 goto err;
230 }
231
232 opt = 1;
233 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) != 0)
234 {
235 printerror(__func__, "could not set SO_REUSEADDR");
236 goto err;
237 }
238
239 sockaddr_compose((struct sockaddr *)&sin4, AF_INET, addr, sport);
240 if(bind(fd, (struct sockaddr *)&sin4, sizeof(sin4)) == -1)
241 {
242 printerror(__func__, "could not bind %s",
243 sockaddr_tostr((struct sockaddr *)&sin4, tmp, sizeof(tmp)));
244 goto err;
245 }
246
247 return fd;
248
249 err:
250 if(fd != -1) scamper_udp4_close(fd);
251 return -1;
252 }
253
scamper_udp4_openraw_fd(const void * addr)254 int scamper_udp4_openraw_fd(const void *addr)
255 {
256 struct sockaddr_in sin4;
257 int hdr, fd;
258 char tmp[32];
259
260 if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
261 {
262 printerror(__func__, "could not open socket");
263 goto err;
264 }
265 hdr = 1;
266 if(setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (void *)&hdr, sizeof(hdr)) == -1)
267 {
268 printerror(__func__, "could not IP_HDRINCL");
269 goto err;
270 }
271 sockaddr_compose((struct sockaddr *)&sin4, AF_INET, addr, 0);
272 if(bind(fd, (struct sockaddr *)&sin4, sizeof(sin4)) == -1)
273 {
274 printerror(__func__, "could not bind %s",
275 sockaddr_tostr((struct sockaddr *)&sin4, tmp, sizeof(tmp)));
276 goto err;
277 }
278
279 return fd;
280
281 err:
282 if(fd != -1) scamper_udp4_close(fd);
283 return -1;
284 }
285
scamper_udp4_openraw(const void * addr)286 int scamper_udp4_openraw(const void *addr)
287 {
288 int fd, opt;
289
290 #if defined(WITHOUT_PRIVSEP)
291 fd = scamper_udp4_openraw_fd(addr);
292 #else
293 fd = scamper_privsep_open_rawudp(addr);
294 #endif
295 if(fd == -1)
296 return -1;
297
298 opt = 65535 + 128;
299 if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&opt, sizeof(opt)) == -1)
300 {
301 printerror(__func__, "could not set SO_SNDBUF");
302 goto err;
303 }
304 return fd;
305
306 err:
307 if(fd != -1) scamper_udp4_close(fd);
308 return -1;
309 }
310