Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/udp.c
2 views
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
* Copyright (c) 1982, 1986, 1988, 1990, 1993
4
* The Regents of the University of California. All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. Neither the name of the University nor the names of its contributors
15
* may be used to endorse or promote products derived from this software
16
* without specific prior written permission.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*
30
* @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
31
* udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
32
*/
33
34
/*
35
* Changes and additions relating to SLiRP
36
* Copyright (c) 1995 Danny Gasparovski.
37
*
38
* Please read the file COPYRIGHT for the
39
* terms and conditions of the copyright.
40
*/
41
42
#include "slirp.h"
43
#include "ip_icmp.h"
44
45
static uint8_t udp_tos(struct socket *so);
46
47
void udp_init(Slirp *slirp)
48
{
49
slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
50
slirp->udp_last_so = &slirp->udb;
51
}
52
53
void udp_cleanup(Slirp *slirp)
54
{
55
struct socket *so, *so_next;
56
57
for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
58
so_next = so->so_next;
59
udp_detach(so);
60
}
61
}
62
63
/* m->m_data points at ip packet header
64
* m->m_len length ip packet
65
* ip->ip_len length data (IPDU)
66
*/
67
void udp_input(register struct mbuf *m, int iphlen)
68
{
69
Slirp *slirp = m->slirp;
70
M_DUP_DEBUG(slirp, m, 0, 0);
71
72
register struct ip *ip;
73
register struct udphdr *uh;
74
int len;
75
struct ip save_ip;
76
struct socket *so;
77
struct sockaddr_storage lhost;
78
struct sockaddr_in *lhost4;
79
int ttl;
80
81
DEBUG_CALL("udp_input");
82
DEBUG_ARG("m = %p", m);
83
DEBUG_ARG("iphlen = %d", iphlen);
84
85
/*
86
* Strip IP options, if any; should skip this,
87
* make available to user, and use on returned packets,
88
* but we don't yet have a way to check the checksum
89
* with options still present.
90
*/
91
if (iphlen > sizeof(struct ip)) {
92
ip_stripoptions(m);
93
iphlen = sizeof(struct ip);
94
}
95
96
/*
97
* Get IP and UDP header together in first mbuf.
98
*/
99
ip = mtod_check(m, iphlen + sizeof(struct udphdr));
100
if (ip == NULL) {
101
goto bad;
102
}
103
uh = (struct udphdr *)((char *)ip + iphlen);
104
105
/*
106
* Make mbuf data length reflect UDP length.
107
* If not enough data to reflect UDP length, drop.
108
*/
109
len = ntohs((uint16_t)uh->uh_ulen);
110
111
if (ip->ip_len != len) {
112
if (len > ip->ip_len) {
113
goto bad;
114
}
115
m_adj(m, len - ip->ip_len);
116
ip->ip_len = len;
117
}
118
119
/*
120
* Save a copy of the IP header in case we want restore it
121
* for sending an ICMP error message in response.
122
*/
123
save_ip = *ip;
124
save_ip.ip_len += iphlen; /* tcp_input subtracts this */
125
126
/*
127
* Checksum extended UDP header and data.
128
*/
129
if (uh->uh_sum) {
130
memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
131
((struct ipovly *)ip)->ih_x1 = 0;
132
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
133
if (cksum(m, len + sizeof(struct ip))) {
134
goto bad;
135
}
136
}
137
138
lhost.ss_family = AF_INET;
139
lhost4 = (struct sockaddr_in *)&lhost;
140
lhost4->sin_addr = ip->ip_src;
141
lhost4->sin_port = uh->uh_sport;
142
143
/*
144
* handle DHCP/BOOTP
145
*/
146
if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
147
(ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
148
ip->ip_dst.s_addr == 0xffffffff)) {
149
bootp_input(m);
150
goto bad;
151
}
152
153
/*
154
* handle TFTP
155
*/
156
if (ntohs(uh->uh_dport) == TFTP_SERVER &&
157
ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
158
m->m_data += iphlen;
159
m->m_len -= iphlen;
160
tftp_input(&lhost, m);
161
m->m_data -= iphlen;
162
m->m_len += iphlen;
163
goto bad;
164
}
165
166
if (slirp->restricted) {
167
goto bad;
168
}
169
170
/*
171
* Locate pcb for datagram.
172
*/
173
so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
174
175
if (so == NULL) {
176
/*
177
* If there's no socket for this packet,
178
* create one
179
*/
180
so = socreate(slirp, IPPROTO_UDP);
181
if (udp_attach(so, AF_INET) == -1) {
182
DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));
183
sofree(so);
184
goto bad;
185
}
186
187
/*
188
* Setup fields
189
*/
190
so->so_lfamily = AF_INET;
191
so->so_laddr = ip->ip_src;
192
so->so_lport = uh->uh_sport;
193
194
if ((so->so_iptos = udp_tos(so)) == 0)
195
so->so_iptos = ip->ip_tos;
196
197
/*
198
* XXXXX Here, check if it's in udpexec_list,
199
* and if it is, do the fork_exec() etc.
200
*/
201
}
202
203
so->so_ffamily = AF_INET;
204
so->so_faddr = ip->ip_dst; /* XXX */
205
so->so_fport = uh->uh_dport; /* XXX */
206
207
iphlen += sizeof(struct udphdr);
208
m->m_len -= iphlen;
209
m->m_data += iphlen;
210
211
/*
212
* Check for TTL
213
*/
214
ttl = save_ip.ip_ttl-1;
215
if (ttl <= 0) {
216
m->m_len += iphlen;
217
m->m_data -= iphlen;
218
*ip = save_ip;
219
DEBUG_MISC("udp ttl exceeded");
220
icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, NULL);
221
goto bad;
222
}
223
setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
224
225
/*
226
* Now we sendto() the packet.
227
*/
228
if (sosendto(so, m) == -1) {
229
m->m_len += iphlen;
230
m->m_data -= iphlen;
231
*ip = save_ip;
232
DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
233
icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
234
goto bad;
235
}
236
237
m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
238
239
/* restore the orig mbuf packet */
240
m->m_len += iphlen;
241
m->m_data -= iphlen;
242
*ip = save_ip;
243
so->so_m = m; /* ICMP backup */
244
245
return;
246
bad:
247
m_free(m);
248
}
249
250
int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
251
struct sockaddr_in *daddr, int iptos)
252
{
253
Slirp *slirp = m->slirp;
254
char addr[INET_ADDRSTRLEN];
255
256
M_DUP_DEBUG(slirp, m, 0, sizeof(struct udpiphdr));
257
258
register struct udpiphdr *ui;
259
int error = 0;
260
261
DEBUG_CALL("udp_output");
262
DEBUG_ARG("so = %p", so);
263
DEBUG_ARG("m = %p", m);
264
DEBUG_ARG("saddr = %s", inet_ntop(AF_INET, &saddr->sin_addr, addr, sizeof(addr)));
265
DEBUG_ARG("daddr = %s", inet_ntop(AF_INET, &daddr->sin_addr, addr, sizeof(addr)));
266
267
/*
268
* Adjust for header
269
*/
270
m->m_data -= sizeof(struct udpiphdr);
271
m->m_len += sizeof(struct udpiphdr);
272
273
/*
274
* Fill in mbuf with extended UDP header
275
* and addresses and length put into network format.
276
*/
277
ui = mtod(m, struct udpiphdr *);
278
memset(&ui->ui_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));
279
ui->ui_x1 = 0;
280
ui->ui_pr = IPPROTO_UDP;
281
ui->ui_len = htons(m->m_len - sizeof(struct ip));
282
/* XXXXX Check for from-one-location sockets, or from-any-location sockets
283
*/
284
ui->ui_src = saddr->sin_addr;
285
ui->ui_dst = daddr->sin_addr;
286
ui->ui_sport = saddr->sin_port;
287
ui->ui_dport = daddr->sin_port;
288
ui->ui_ulen = ui->ui_len;
289
290
/*
291
* Stuff checksum and output datagram.
292
*/
293
ui->ui_sum = 0;
294
if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
295
ui->ui_sum = 0xffff;
296
((struct ip *)ui)->ip_len = m->m_len;
297
298
((struct ip *)ui)->ip_ttl = IPDEFTTL;
299
((struct ip *)ui)->ip_tos = iptos;
300
301
error = ip_output(so, m);
302
303
return (error);
304
}
305
306
int udp_attach(struct socket *so, unsigned short af)
307
{
308
so->s = slirp_socket(af, SOCK_DGRAM, 0);
309
if (so->s != -1) {
310
if (slirp_bind_outbound(so, af) != 0) {
311
// bind failed - close socket
312
closesocket(so->s);
313
so->s = -1;
314
return -1;
315
}
316
317
#ifdef __linux__
318
{
319
int opt = 1;
320
switch (af) {
321
case AF_INET:
322
setsockopt(so->s, IPPROTO_IP, IP_RECVERR, &opt, sizeof(opt));
323
break;
324
case AF_INET6:
325
setsockopt(so->s, IPPROTO_IPV6, IPV6_RECVERR, &opt, sizeof(opt));
326
break;
327
default:
328
g_assert_not_reached();
329
}
330
}
331
#endif
332
333
so->so_expire = curtime + SO_EXPIRE;
334
slirp_insque(so, &so->slirp->udb);
335
}
336
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
337
return (so->s);
338
}
339
340
void udp_detach(struct socket *so)
341
{
342
so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
343
closesocket(so->s);
344
sofree(so);
345
}
346
347
static const struct tos_t udptos[] = { { 0, 53, IPTOS_LOWDELAY, 0 }, /* DNS */
348
{ 0, 0, 0, 0 } };
349
350
static uint8_t udp_tos(struct socket *so)
351
{
352
int i = 0;
353
354
while (udptos[i].tos) {
355
if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
356
(udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
357
if (so->slirp->enable_emu)
358
so->so_emu = udptos[i].emu;
359
return udptos[i].tos;
360
}
361
i++;
362
}
363
364
return 0;
365
}
366
367
struct socket *udpx_listen(Slirp *slirp,
368
const struct sockaddr *haddr, socklen_t haddrlen,
369
const struct sockaddr *laddr, socklen_t laddrlen,
370
int flags)
371
{
372
struct socket *so;
373
socklen_t addrlen;
374
int save_errno;
375
376
so = socreate(slirp, IPPROTO_UDP);
377
so->s = slirp_socket(haddr->sa_family, SOCK_DGRAM, 0);
378
if (so->s < 0) {
379
save_errno = errno;
380
sofree(so);
381
errno = save_errno;
382
return NULL;
383
}
384
if (haddr->sa_family == AF_INET6)
385
slirp_socket_set_v6only(so->s, (flags & SS_HOSTFWD_V6ONLY) != 0);
386
so->so_expire = curtime + SO_EXPIRE;
387
slirp_insque(so, &slirp->udb);
388
389
if (bind(so->s, haddr, haddrlen) < 0) {
390
save_errno = errno;
391
udp_detach(so);
392
errno = save_errno;
393
return NULL;
394
}
395
slirp_socket_set_fast_reuse(so->s);
396
397
addrlen = sizeof(so->fhost);
398
getsockname(so->s, &so->fhost.sa, &addrlen);
399
sotranslate_accept(so);
400
401
sockaddr_copy(&so->lhost.sa, sizeof(so->lhost), laddr, laddrlen);
402
403
if (flags != SS_FACCEPTONCE)
404
so->so_expire = 0;
405
so->so_state &= SS_PERSISTENT_MASK;
406
so->so_state |= SS_ISFCONNECTED | flags;
407
408
return so;
409
}
410
411
struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
412
uint32_t laddr, unsigned lport, int flags)
413
{
414
struct sockaddr_in hsa, lsa;
415
416
memset(&hsa, 0, sizeof(hsa));
417
hsa.sin_family = AF_INET;
418
hsa.sin_addr.s_addr = haddr;
419
hsa.sin_port = hport;
420
421
memset(&lsa, 0, sizeof(lsa));
422
lsa.sin_family = AF_INET;
423
lsa.sin_addr.s_addr = laddr;
424
lsa.sin_port = lport;
425
426
return udpx_listen(slirp, (const struct sockaddr *) &hsa, sizeof(hsa), (struct sockaddr *) &lsa, sizeof(lsa), flags);
427
}
428
429