]>
Commit | Line | Data |
---|---|---|
3e6d35e5 | 1 | /* SPDX-License-Identifier: BSD-3-Clause */ |
f0cbd3ec FB |
2 | /* |
3 | * Copyright (c) 1995 Danny Gasparovski. | |
f0cbd3ec FB |
4 | */ |
5 | ||
a9c94277 | 6 | #include "slirp.h" |
f0cbd3ec | 7 | #include "ip_icmp.h" |
ec530c81 FB |
8 | #ifdef __sun__ |
9 | #include <sys/filio.h> | |
10 | #endif | |
f0cbd3ec | 11 | |
9634d903 BS |
12 | static void sofcantrcvmore(struct socket *so); |
13 | static void sofcantsendmore(struct socket *so); | |
14 | ||
8a87f121 GS |
15 | struct socket *solookup(struct socket **last, struct socket *head, |
16 | struct sockaddr_storage *lhost, struct sockaddr_storage *fhost) | |
f0cbd3ec | 17 | { |
a5fd24aa | 18 | struct socket *so = *last; |
5fafdf24 | 19 | |
a5fd24aa | 20 | /* Optimisation */ |
8a87f121 GS |
21 | if (so != head && sockaddr_equal(&(so->lhost.ss), lhost) |
22 | && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { | |
a5fd24aa GS |
23 | return so; |
24 | } | |
5fafdf24 | 25 | |
a5fd24aa | 26 | for (so = head->so_next; so != head; so = so->so_next) { |
8a87f121 GS |
27 | if (sockaddr_equal(&(so->lhost.ss), lhost) |
28 | && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { | |
a5fd24aa GS |
29 | *last = so; |
30 | return so; | |
31 | } | |
32 | } | |
5fafdf24 | 33 | |
a5fd24aa | 34 | return (struct socket *)NULL; |
f0cbd3ec FB |
35 | } |
36 | ||
37 | /* | |
38 | * Create a new socket, initialise the fields | |
39 | * It is the responsibility of the caller to | |
40 | * insque() it into the correct linked-list | |
41 | */ | |
42 | struct socket * | |
460fec67 | 43 | socreate(Slirp *slirp) |
f0cbd3ec | 44 | { |
84ec9bfa | 45 | struct socket *so = g_new(struct socket, 1); |
5fafdf24 | 46 | |
f0cbd3ec FB |
47 | memset(so, 0, sizeof(struct socket)); |
48 | so->so_state = SS_NOFDREF; | |
49 | so->s = -1; | |
460fec67 | 50 | so->slirp = slirp; |
7bd43ec2 | 51 | so->pollfds_idx = -1; |
84ec9bfa PM |
52 | |
53 | return so; | |
f0cbd3ec FB |
54 | } |
55 | ||
1201d308 ST |
56 | /* |
57 | * Remove references to so from the given message queue. | |
58 | */ | |
59 | static void | |
60 | soqfree(struct socket *so, struct quehead *qh) | |
61 | { | |
62 | struct mbuf *ifq; | |
63 | ||
64 | for (ifq = (struct mbuf *) qh->qh_link; | |
65 | (struct quehead *) ifq != qh; | |
66 | ifq = ifq->ifq_next) { | |
67 | if (ifq->ifq_so == so) { | |
68 | struct mbuf *ifm; | |
69 | ifq->ifq_so = NULL; | |
70 | for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) { | |
71 | ifm->ifq_so = NULL; | |
72 | } | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
f0cbd3ec FB |
77 | /* |
78 | * remque and free a socket, clobber cache | |
79 | */ | |
80 | void | |
511d2b14 | 81 | sofree(struct socket *so) |
f0cbd3ec | 82 | { |
460fec67 | 83 | Slirp *slirp = so->slirp; |
ea64d5f0 | 84 | |
1201d308 ST |
85 | soqfree(so, &slirp->if_fastq); |
86 | soqfree(so, &slirp->if_batchq); | |
460fec67 | 87 | |
460fec67 JK |
88 | if (so == slirp->tcp_last_so) { |
89 | slirp->tcp_last_so = &slirp->tcb; | |
90 | } else if (so == slirp->udp_last_so) { | |
91 | slirp->udp_last_so = &slirp->udb; | |
e6d43cfb JK |
92 | } else if (so == slirp->icmp_last_so) { |
93 | slirp->icmp_last_so = &slirp->icmp; | |
460fec67 | 94 | } |
f0cbd3ec | 95 | m_free(so->so_m); |
5fafdf24 TS |
96 | |
97 | if(so->so_next && so->so_prev) | |
f0cbd3ec FB |
98 | remque(so); /* crashes if so is not in a queue */ |
99 | ||
7d824696 MAL |
100 | if (so->so_tcpcb) { |
101 | free(so->so_tcpcb); | |
102 | } | |
84ec9bfa | 103 | g_free(so); |
f0cbd3ec FB |
104 | } |
105 | ||
e1c5a2b3 | 106 | size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np) |
f0cbd3ec | 107 | { |
e1c5a2b3 | 108 | int n, lss, total; |
f0cbd3ec FB |
109 | struct sbuf *sb = &so->so_snd; |
110 | int len = sb->sb_datalen - sb->sb_cc; | |
f0cbd3ec | 111 | int mss = so->so_tcpcb->t_maxseg; |
5fafdf24 | 112 | |
e1c5a2b3 | 113 | DEBUG_CALL("sopreprbuf"); |
ecc804ca | 114 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 115 | |
e1c5a2b3 AL |
116 | if (len <= 0) |
117 | return 0; | |
118 | ||
f0cbd3ec | 119 | iov[0].iov_base = sb->sb_wptr; |
66029f6a BS |
120 | iov[1].iov_base = NULL; |
121 | iov[1].iov_len = 0; | |
f0cbd3ec FB |
122 | if (sb->sb_wptr < sb->sb_rptr) { |
123 | iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; | |
124 | /* Should never succeed, but... */ | |
125 | if (iov[0].iov_len > len) | |
126 | iov[0].iov_len = len; | |
127 | if (iov[0].iov_len > mss) | |
128 | iov[0].iov_len -= iov[0].iov_len%mss; | |
129 | n = 1; | |
130 | } else { | |
131 | iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; | |
132 | /* Should never succeed, but... */ | |
133 | if (iov[0].iov_len > len) iov[0].iov_len = len; | |
134 | len -= iov[0].iov_len; | |
135 | if (len) { | |
136 | iov[1].iov_base = sb->sb_data; | |
137 | iov[1].iov_len = sb->sb_rptr - sb->sb_data; | |
138 | if(iov[1].iov_len > len) | |
139 | iov[1].iov_len = len; | |
140 | total = iov[0].iov_len + iov[1].iov_len; | |
141 | if (total > mss) { | |
142 | lss = total%mss; | |
143 | if (iov[1].iov_len > lss) { | |
144 | iov[1].iov_len -= lss; | |
145 | n = 2; | |
146 | } else { | |
147 | lss -= iov[1].iov_len; | |
148 | iov[0].iov_len -= lss; | |
149 | n = 1; | |
150 | } | |
151 | } else | |
152 | n = 2; | |
153 | } else { | |
154 | if (iov[0].iov_len > mss) | |
155 | iov[0].iov_len -= iov[0].iov_len%mss; | |
156 | n = 1; | |
157 | } | |
158 | } | |
e1c5a2b3 AL |
159 | if (np) |
160 | *np = n; | |
161 | ||
162 | return iov[0].iov_len + (n - 1) * iov[1].iov_len; | |
163 | } | |
164 | ||
165 | /* | |
166 | * Read from so's socket into sb_snd, updating all relevant sbuf fields | |
167 | * NOTE: This will only be called if it is select()ed for reading, so | |
168 | * a read() of 0 (or less) means it's disconnected | |
169 | */ | |
170 | int | |
511d2b14 | 171 | soread(struct socket *so) |
e1c5a2b3 AL |
172 | { |
173 | int n, nn; | |
174 | struct sbuf *sb = &so->so_snd; | |
175 | struct iovec iov[2]; | |
176 | ||
177 | DEBUG_CALL("soread"); | |
ecc804ca | 178 | DEBUG_ARG("so = %p", so); |
e1c5a2b3 AL |
179 | |
180 | /* | |
181 | * No need to check if there's enough room to read. | |
182 | * soread wouldn't have been called if there weren't | |
183 | */ | |
184 | sopreprbuf(so, iov, &n); | |
5fafdf24 | 185 | |
fdbfba8c | 186 | nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); |
f0cbd3ec FB |
187 | if (nn <= 0) { |
188 | if (nn < 0 && (errno == EINTR || errno == EAGAIN)) | |
189 | return 0; | |
190 | else { | |
27d92ebc | 191 | int err; |
93a972f8 GG |
192 | socklen_t elen = sizeof err; |
193 | struct sockaddr_storage addr; | |
194 | struct sockaddr *paddr = (struct sockaddr *) &addr; | |
195 | socklen_t alen = sizeof addr; | |
27d92ebc EI |
196 | |
197 | err = errno; | |
198 | if (nn == 0) { | |
93a972f8 GG |
199 | if (getpeername(so->s, paddr, &alen) < 0) { |
200 | err = errno; | |
201 | } else { | |
fdbfba8c | 202 | getsockopt(so->s, SOL_SOCKET, SO_ERROR, |
93a972f8 GG |
203 | &err, &elen); |
204 | } | |
27d92ebc EI |
205 | } |
206 | ||
226ea7a9 MAL |
207 | DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s", |
208 | nn, errno,strerror(errno)); | |
f0cbd3ec | 209 | sofcantrcvmore(so); |
27d92ebc | 210 | |
6625d83a | 211 | if (err == ECONNRESET || err == ECONNREFUSED |
27d92ebc EI |
212 | || err == ENOTCONN || err == EPIPE) { |
213 | tcp_drop(sototcpcb(so), err); | |
214 | } else { | |
215 | tcp_sockclosed(sototcpcb(so)); | |
216 | } | |
f0cbd3ec FB |
217 | return -1; |
218 | } | |
219 | } | |
5fafdf24 | 220 | |
f0cbd3ec FB |
221 | /* |
222 | * If there was no error, try and read the second time round | |
223 | * We read again if n = 2 (ie, there's another part of the buffer) | |
224 | * and we read as much as we could in the first read | |
225 | * We don't test for <= 0 this time, because there legitimately | |
226 | * might not be any more data (since the socket is non-blocking), | |
227 | * a close will be detected on next iteration. | |
cb8d4c8f | 228 | * A return of -1 won't (shouldn't) happen, since it didn't happen above |
f0cbd3ec | 229 | */ |
17444c9c FB |
230 | if (n == 2 && nn == iov[0].iov_len) { |
231 | int ret; | |
fdbfba8c | 232 | ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); |
17444c9c FB |
233 | if (ret > 0) |
234 | nn += ret; | |
235 | } | |
5fafdf24 | 236 | |
226ea7a9 | 237 | DEBUG_MISC(" ... read nn = %d bytes", nn); |
5fafdf24 | 238 | |
f0cbd3ec FB |
239 | /* Update fields */ |
240 | sb->sb_cc += nn; | |
241 | sb->sb_wptr += nn; | |
242 | if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) | |
243 | sb->sb_wptr -= sb->sb_datalen; | |
244 | return nn; | |
245 | } | |
5fafdf24 | 246 | |
e1c5a2b3 AL |
247 | int soreadbuf(struct socket *so, const char *buf, int size) |
248 | { | |
249 | int n, nn, copy = size; | |
250 | struct sbuf *sb = &so->so_snd; | |
251 | struct iovec iov[2]; | |
252 | ||
253 | DEBUG_CALL("soreadbuf"); | |
ecc804ca | 254 | DEBUG_ARG("so = %p", so); |
e1c5a2b3 AL |
255 | |
256 | /* | |
257 | * No need to check if there's enough room to read. | |
258 | * soread wouldn't have been called if there weren't | |
259 | */ | |
260 | if (sopreprbuf(so, iov, &n) < size) | |
261 | goto err; | |
262 | ||
263 | nn = MIN(iov[0].iov_len, copy); | |
264 | memcpy(iov[0].iov_base, buf, nn); | |
265 | ||
266 | copy -= nn; | |
267 | buf += nn; | |
268 | ||
269 | if (copy == 0) | |
270 | goto done; | |
271 | ||
272 | memcpy(iov[1].iov_base, buf, copy); | |
273 | ||
274 | done: | |
275 | /* Update fields */ | |
276 | sb->sb_cc += size; | |
277 | sb->sb_wptr += size; | |
278 | if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) | |
279 | sb->sb_wptr -= sb->sb_datalen; | |
280 | return size; | |
281 | err: | |
282 | ||
283 | sofcantrcvmore(so); | |
284 | tcp_sockclosed(sototcpcb(so)); | |
b0866f0c | 285 | g_critical("soreadbuf buffer too small"); |
e1c5a2b3 AL |
286 | return -1; |
287 | } | |
288 | ||
f0cbd3ec FB |
289 | /* |
290 | * Get urgent data | |
5fafdf24 | 291 | * |
f0cbd3ec FB |
292 | * When the socket is created, we set it SO_OOBINLINE, |
293 | * so when OOB data arrives, we soread() it and everything | |
294 | * in the send buffer is sent as urgent data | |
295 | */ | |
bfb1ac14 | 296 | int |
511d2b14 | 297 | sorecvoob(struct socket *so) |
f0cbd3ec FB |
298 | { |
299 | struct tcpcb *tp = sototcpcb(so); | |
bfb1ac14 | 300 | int ret; |
f0cbd3ec FB |
301 | |
302 | DEBUG_CALL("sorecvoob"); | |
ecc804ca | 303 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 304 | |
f0cbd3ec FB |
305 | /* |
306 | * We take a guess at how much urgent data has arrived. | |
307 | * In most situations, when urgent data arrives, the next | |
308 | * read() should get all the urgent data. This guess will | |
309 | * be wrong however if more data arrives just after the | |
5fafdf24 | 310 | * urgent data, or the read() doesn't return all the |
f0cbd3ec FB |
311 | * urgent data. |
312 | */ | |
bfb1ac14 SL |
313 | ret = soread(so); |
314 | if (ret > 0) { | |
315 | tp->snd_up = tp->snd_una + so->so_snd.sb_cc; | |
316 | tp->t_force = 1; | |
317 | tcp_output(tp); | |
318 | tp->t_force = 0; | |
319 | } | |
320 | ||
321 | return ret; | |
f0cbd3ec FB |
322 | } |
323 | ||
324 | /* | |
325 | * Send urgent data | |
326 | * There's a lot duplicated code here, but... | |
327 | */ | |
328 | int | |
511d2b14 | 329 | sosendoob(struct socket *so) |
f0cbd3ec FB |
330 | { |
331 | struct sbuf *sb = &so->so_rcv; | |
332 | char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ | |
5fafdf24 | 333 | |
c7950fb3 | 334 | int n; |
5fafdf24 | 335 | |
f0cbd3ec | 336 | DEBUG_CALL("sosendoob"); |
ecc804ca | 337 | DEBUG_ARG("so = %p", so); |
f0cbd3ec | 338 | DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); |
5fafdf24 | 339 | |
f0cbd3ec FB |
340 | if (so->so_urgc > 2048) |
341 | so->so_urgc = 2048; /* XXXX */ | |
5fafdf24 | 342 | |
f0cbd3ec FB |
343 | if (sb->sb_rptr < sb->sb_wptr) { |
344 | /* We can send it directly */ | |
e1c5a2b3 | 345 | n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ |
f0cbd3ec | 346 | } else { |
5fafdf24 | 347 | /* |
f0cbd3ec FB |
348 | * Since there's no sendv or sendtov like writev, |
349 | * we must copy all data to a linear buffer then | |
350 | * send it all | |
351 | */ | |
0b466065 | 352 | uint32_t urgc = so->so_urgc; |
c7950fb3 | 353 | int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; |
0b466065 PM |
354 | if (len > urgc) { |
355 | len = urgc; | |
356 | } | |
f0cbd3ec | 357 | memcpy(buff, sb->sb_rptr, len); |
0b466065 PM |
358 | urgc -= len; |
359 | if (urgc) { | |
f0cbd3ec | 360 | n = sb->sb_wptr - sb->sb_data; |
0b466065 PM |
361 | if (n > urgc) { |
362 | n = urgc; | |
363 | } | |
f0cbd3ec | 364 | memcpy((buff + len), sb->sb_data, n); |
f0cbd3ec FB |
365 | len += n; |
366 | } | |
e1c5a2b3 | 367 | n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ |
f0cbd3ec | 368 | #ifdef DEBUG |
c7950fb3 | 369 | if (n != len) { |
226ea7a9 | 370 | DEBUG_ERROR("Didn't send all data urgently XXXXX"); |
c7950fb3 | 371 | } |
3b46e624 | 372 | #endif |
c7950fb3 ST |
373 | } |
374 | ||
0b466065 PM |
375 | if (n < 0) { |
376 | return n; | |
f0cbd3ec | 377 | } |
0b466065 | 378 | so->so_urgc -= n; |
226ea7a9 | 379 | DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n, so->so_urgc); |
5fafdf24 | 380 | |
f0cbd3ec FB |
381 | sb->sb_cc -= n; |
382 | sb->sb_rptr += n; | |
383 | if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) | |
384 | sb->sb_rptr -= sb->sb_datalen; | |
5fafdf24 | 385 | |
f0cbd3ec FB |
386 | return n; |
387 | } | |
388 | ||
389 | /* | |
5fafdf24 | 390 | * Write data from so_rcv to so's socket, |
f0cbd3ec FB |
391 | * updating all sbuf field as necessary |
392 | */ | |
393 | int | |
511d2b14 | 394 | sowrite(struct socket *so) |
f0cbd3ec FB |
395 | { |
396 | int n,nn; | |
397 | struct sbuf *sb = &so->so_rcv; | |
398 | int len = sb->sb_cc; | |
399 | struct iovec iov[2]; | |
5fafdf24 | 400 | |
f0cbd3ec | 401 | DEBUG_CALL("sowrite"); |
ecc804ca | 402 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 403 | |
f0cbd3ec | 404 | if (so->so_urgc) { |
75cb298d PM |
405 | uint32_t expected = so->so_urgc; |
406 | if (sosendoob(so) < expected) { | |
407 | /* Treat a short write as a fatal error too, | |
408 | * rather than continuing on and sending the urgent | |
409 | * data as if it were non-urgent and leaving the | |
410 | * so_urgc count wrong. | |
411 | */ | |
412 | goto err_disconnected; | |
413 | } | |
f0cbd3ec FB |
414 | if (sb->sb_cc == 0) |
415 | return 0; | |
416 | } | |
417 | ||
418 | /* | |
419 | * No need to check if there's something to write, | |
420 | * sowrite wouldn't have been called otherwise | |
421 | */ | |
5fafdf24 | 422 | |
f0cbd3ec | 423 | iov[0].iov_base = sb->sb_rptr; |
66029f6a BS |
424 | iov[1].iov_base = NULL; |
425 | iov[1].iov_len = 0; | |
f0cbd3ec FB |
426 | if (sb->sb_rptr < sb->sb_wptr) { |
427 | iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; | |
428 | /* Should never succeed, but... */ | |
429 | if (iov[0].iov_len > len) iov[0].iov_len = len; | |
430 | n = 1; | |
431 | } else { | |
432 | iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; | |
433 | if (iov[0].iov_len > len) iov[0].iov_len = len; | |
434 | len -= iov[0].iov_len; | |
435 | if (len) { | |
436 | iov[1].iov_base = sb->sb_data; | |
437 | iov[1].iov_len = sb->sb_wptr - sb->sb_data; | |
438 | if (iov[1].iov_len > len) iov[1].iov_len = len; | |
439 | n = 2; | |
440 | } else | |
441 | n = 1; | |
442 | } | |
443 | /* Check if there's urgent data to send, and if so, send it */ | |
444 | ||
e1c5a2b3 | 445 | nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); |
f0cbd3ec FB |
446 | /* This should never happen, but people tell me it does *shrug* */ |
447 | if (nn < 0 && (errno == EAGAIN || errno == EINTR)) | |
448 | return 0; | |
5fafdf24 | 449 | |
f0cbd3ec | 450 | if (nn <= 0) { |
75cb298d | 451 | goto err_disconnected; |
f0cbd3ec | 452 | } |
5fafdf24 | 453 | |
3bc2175d FB |
454 | if (n == 2 && nn == iov[0].iov_len) { |
455 | int ret; | |
e1c5a2b3 | 456 | ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0); |
3bc2175d FB |
457 | if (ret > 0) |
458 | nn += ret; | |
459 | } | |
226ea7a9 | 460 | DEBUG_MISC(" ... wrote nn = %d bytes", nn); |
5fafdf24 | 461 | |
f0cbd3ec FB |
462 | /* Update sbuf */ |
463 | sb->sb_cc -= nn; | |
464 | sb->sb_rptr += nn; | |
465 | if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) | |
466 | sb->sb_rptr -= sb->sb_datalen; | |
5fafdf24 | 467 | |
f0cbd3ec FB |
468 | /* |
469 | * If in DRAIN mode, and there's no more data, set | |
470 | * it CANTSENDMORE | |
471 | */ | |
472 | if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) | |
473 | sofcantsendmore(so); | |
5fafdf24 | 474 | |
f0cbd3ec | 475 | return nn; |
75cb298d PM |
476 | |
477 | err_disconnected: | |
226ea7a9 | 478 | DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d", |
2afbb788 | 479 | so->so_state, errno); |
75cb298d PM |
480 | sofcantsendmore(so); |
481 | tcp_sockclosed(sototcpcb(so)); | |
482 | return -1; | |
f0cbd3ec FB |
483 | } |
484 | ||
485 | /* | |
486 | * recvfrom() a UDP socket | |
487 | */ | |
488 | void | |
511d2b14 | 489 | sorecvfrom(struct socket *so) |
f0cbd3ec | 490 | { |
eae303ff | 491 | struct sockaddr_storage addr; |
5379229a | 492 | struct sockaddr_storage saddr, daddr; |
eae303ff | 493 | socklen_t addrlen = sizeof(struct sockaddr_storage); |
5fafdf24 | 494 | |
f0cbd3ec | 495 | DEBUG_CALL("sorecvfrom"); |
ecc804ca | 496 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 497 | |
f0cbd3ec FB |
498 | if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ |
499 | char buff[256]; | |
500 | int len; | |
3b46e624 | 501 | |
5fafdf24 | 502 | len = recvfrom(so->s, buff, 256, 0, |
f0cbd3ec FB |
503 | (struct sockaddr *)&addr, &addrlen); |
504 | /* XXX Check if reply is "correct"? */ | |
3b46e624 | 505 | |
f0cbd3ec | 506 | if(len == -1 || len == 0) { |
d7df0b41 | 507 | uint8_t code=ICMP_UNREACH_PORT; |
f0cbd3ec FB |
508 | |
509 | if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; | |
510 | else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; | |
3b46e624 | 511 | |
226ea7a9 | 512 | DEBUG_MISC(" udp icmp rx errno = %d-%s", |
2afbb788 | 513 | errno,strerror(errno)); |
de40abfe | 514 | icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); |
f0cbd3ec FB |
515 | } else { |
516 | icmp_reflect(so->so_m); | |
511d2b14 | 517 | so->so_m = NULL; /* Don't m_free() it again! */ |
f0cbd3ec FB |
518 | } |
519 | /* No need for this socket anymore, udp_detach it */ | |
520 | udp_detach(so); | |
521 | } else { /* A "normal" UDP packet */ | |
522 | struct mbuf *m; | |
c5b76b38 BS |
523 | int len; |
524 | #ifdef _WIN32 | |
525 | unsigned long n; | |
526 | #else | |
527 | int n; | |
528 | #endif | |
f0cbd3ec | 529 | |
6c419a1e VL |
530 | if (ioctlsocket(so->s, FIONREAD, &n) != 0) { |
531 | DEBUG_MISC(" ioctlsocket errno = %d-%s\n", | |
532 | errno,strerror(errno)); | |
533 | return; | |
534 | } | |
535 | if (n == 0) { | |
536 | return; | |
537 | } | |
538 | ||
460fec67 JK |
539 | m = m_get(so->slirp); |
540 | if (!m) { | |
541 | return; | |
542 | } | |
98c63057 GS |
543 | switch (so->so_ffamily) { |
544 | case AF_INET: | |
545 | m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr); | |
546 | break; | |
547 | case AF_INET6: | |
548 | m->m_data += IF_MAXLINKHDR + sizeof(struct ip6) | |
549 | + sizeof(struct udphdr); | |
550 | break; | |
551 | default: | |
552 | g_assert_not_reached(); | |
553 | break; | |
554 | } | |
3b46e624 | 555 | |
5fafdf24 | 556 | /* |
f0cbd3ec FB |
557 | * XXX Shouldn't FIONREAD packets destined for port 53, |
558 | * but I don't know the max packet size for DNS lookups | |
559 | */ | |
560 | len = M_FREEROOM(m); | |
561 | /* if (so->so_fport != htons(53)) { */ | |
3b46e624 | 562 | |
f0cbd3ec FB |
563 | if (n > len) { |
564 | n = (m->m_data - m->m_dat) + m->m_len + n + 1; | |
565 | m_inc(m, n); | |
566 | len = M_FREEROOM(m); | |
567 | } | |
568 | /* } */ | |
3b46e624 | 569 | |
f0cbd3ec FB |
570 | m->m_len = recvfrom(so->s, m->m_data, len, 0, |
571 | (struct sockaddr *)&addr, &addrlen); | |
226ea7a9 | 572 | DEBUG_MISC(" did recvfrom %d, errno = %d-%s", |
2afbb788 | 573 | m->m_len, errno,strerror(errno)); |
f0cbd3ec | 574 | if(m->m_len<0) { |
15d62af4 GS |
575 | /* Report error as ICMP */ |
576 | switch (so->so_lfamily) { | |
577 | uint8_t code; | |
578 | case AF_INET: | |
579 | code = ICMP_UNREACH_PORT; | |
580 | ||
581 | if (errno == EHOSTUNREACH) { | |
582 | code = ICMP_UNREACH_HOST; | |
583 | } else if (errno == ENETUNREACH) { | |
584 | code = ICMP_UNREACH_NET; | |
585 | } | |
586 | ||
226ea7a9 | 587 | DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code); |
15d62af4 GS |
588 | icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); |
589 | break; | |
590 | case AF_INET6: | |
591 | code = ICMP6_UNREACH_PORT; | |
592 | ||
593 | if (errno == EHOSTUNREACH) { | |
594 | code = ICMP6_UNREACH_ADDRESS; | |
595 | } else if (errno == ENETUNREACH) { | |
596 | code = ICMP6_UNREACH_NO_ROUTE; | |
597 | } | |
598 | ||
226ea7a9 | 599 | DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code); |
15d62af4 GS |
600 | icmp6_send_error(so->so_m, ICMP6_UNREACH, code); |
601 | break; | |
602 | default: | |
603 | g_assert_not_reached(); | |
604 | break; | |
605 | } | |
f0cbd3ec FB |
606 | m_free(m); |
607 | } else { | |
608 | /* | |
609 | * Hack: domain name lookup will be used the most for UDP, | |
610 | * and since they'll only be used once there's no need | |
611 | * for the 4 minute (or whatever) timeout... So we time them | |
612 | * out much quicker (10 seconds for now...) | |
613 | */ | |
614 | if (so->so_expire) { | |
615 | if (so->so_fport == htons(53)) | |
616 | so->so_expire = curtime + SO_EXPIREFAST; | |
617 | else | |
618 | so->so_expire = curtime + SO_EXPIRE; | |
619 | } | |
620 | ||
5fafdf24 | 621 | /* |
f0cbd3ec | 622 | * If this packet was destined for CTL_ADDR, |
5379229a | 623 | * make it look like that's where it came from |
f0cbd3ec | 624 | */ |
5379229a GS |
625 | saddr = addr; |
626 | sotranslate_in(so, &saddr); | |
627 | daddr = so->lhost.ss; | |
628 | ||
eae303ff GS |
629 | switch (so->so_ffamily) { |
630 | case AF_INET: | |
5379229a GS |
631 | udp_output(so, m, (struct sockaddr_in *) &saddr, |
632 | (struct sockaddr_in *) &daddr, | |
633 | so->so_iptos); | |
eae303ff | 634 | break; |
15d62af4 GS |
635 | case AF_INET6: |
636 | udp6_output(so, m, (struct sockaddr_in6 *) &saddr, | |
637 | (struct sockaddr_in6 *) &daddr); | |
638 | break; | |
eae303ff | 639 | default: |
15d62af4 | 640 | g_assert_not_reached(); |
eae303ff GS |
641 | break; |
642 | } | |
f0cbd3ec FB |
643 | } /* rx error */ |
644 | } /* if ping packet */ | |
645 | } | |
646 | ||
647 | /* | |
648 | * sendto() a socket | |
649 | */ | |
650 | int | |
511d2b14 | 651 | sosendto(struct socket *so, struct mbuf *m) |
f0cbd3ec FB |
652 | { |
653 | int ret; | |
5379229a | 654 | struct sockaddr_storage addr; |
f0cbd3ec FB |
655 | |
656 | DEBUG_CALL("sosendto"); | |
ecc804ca SW |
657 | DEBUG_ARG("so = %p", so); |
658 | DEBUG_ARG("m = %p", m); | |
5fafdf24 | 659 | |
5379229a GS |
660 | addr = so->fhost.ss; |
661 | DEBUG_CALL(" sendto()ing)"); | |
662 | sotranslate_out(so, &addr); | |
5fafdf24 | 663 | |
f0cbd3ec FB |
664 | /* Don't care what port we get */ |
665 | ret = sendto(so->s, m->m_data, m->m_len, 0, | |
0d48dfed | 666 | (struct sockaddr *)&addr, sockaddr_size(&addr)); |
f0cbd3ec FB |
667 | if (ret < 0) |
668 | return -1; | |
5fafdf24 | 669 | |
f0cbd3ec FB |
670 | /* |
671 | * Kill the socket if there's no reply in 4 minutes, | |
672 | * but only if it's an expirable socket | |
673 | */ | |
674 | if (so->so_expire) | |
675 | so->so_expire = curtime + SO_EXPIRE; | |
f932b6ce JK |
676 | so->so_state &= SS_PERSISTENT_MASK; |
677 | so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */ | |
f0cbd3ec FB |
678 | return 0; |
679 | } | |
680 | ||
681 | /* | |
3c6a0580 | 682 | * Listen for incoming TCP connections |
f0cbd3ec FB |
683 | */ |
684 | struct socket * | |
d7df0b41 MAL |
685 | tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr, |
686 | unsigned lport, int flags) | |
f0cbd3ec | 687 | { |
ffe02f55 | 688 | /* TODO: IPv6 */ |
f0cbd3ec FB |
689 | struct sockaddr_in addr; |
690 | struct socket *so; | |
242acf3a AZ |
691 | int s, opt = 1; |
692 | socklen_t addrlen = sizeof(addr); | |
ab07b980 | 693 | memset(&addr, 0, addrlen); |
f0cbd3ec | 694 | |
3c6a0580 | 695 | DEBUG_CALL("tcp_listen"); |
8ee2022b | 696 | DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr})); |
3ad9319f | 697 | DEBUG_ARG("hport = %d", ntohs(hport)); |
8ee2022b | 698 | DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr})); |
3ad9319f | 699 | DEBUG_ARG("lport = %d", ntohs(lport)); |
f0cbd3ec | 700 | DEBUG_ARG("flags = %x", flags); |
5fafdf24 | 701 | |
460fec67 | 702 | so = socreate(slirp); |
5fafdf24 | 703 | |
f0cbd3ec FB |
704 | /* Don't tcp_attach... we don't need so_snd nor so_rcv */ |
705 | if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { | |
84ec9bfa PM |
706 | g_free(so); |
707 | return NULL; | |
f0cbd3ec | 708 | } |
460fec67 | 709 | insque(so, &slirp->tcb); |
5fafdf24 TS |
710 | |
711 | /* | |
f0cbd3ec FB |
712 | * SS_FACCEPTONCE sockets must time out. |
713 | */ | |
714 | if (flags & SS_FACCEPTONCE) | |
715 | so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; | |
5fafdf24 | 716 | |
f932b6ce JK |
717 | so->so_state &= SS_PERSISTENT_MASK; |
718 | so->so_state |= (SS_FACCEPTCONN | flags); | |
eae303ff | 719 | so->so_lfamily = AF_INET; |
f0cbd3ec FB |
720 | so->so_lport = lport; /* Kept in network format */ |
721 | so->so_laddr.s_addr = laddr; /* Ditto */ | |
5fafdf24 | 722 | |
f0cbd3ec | 723 | addr.sin_family = AF_INET; |
3c6a0580 JK |
724 | addr.sin_addr.s_addr = haddr; |
725 | addr.sin_port = hport; | |
5fafdf24 | 726 | |
707bd47e MAL |
727 | if (((s = slirp_socket(AF_INET,SOCK_STREAM,0)) < 0) || |
728 | (slirp_socket_set_fast_reuse(s) < 0) || | |
f0cbd3ec FB |
729 | (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || |
730 | (listen(s,1) < 0)) { | |
731 | int tmperrno = errno; /* Don't clobber the real reason we failed */ | |
3b46e624 | 732 | |
bd5d2353 | 733 | if (s >= 0) { |
fdbfba8c | 734 | closesocket(s); |
bd5d2353 | 735 | } |
f0cbd3ec FB |
736 | sofree(so); |
737 | /* Restore the real errno */ | |
02d2c54c FB |
738 | #ifdef _WIN32 |
739 | WSASetLastError(tmperrno); | |
740 | #else | |
f0cbd3ec | 741 | errno = tmperrno; |
02d2c54c | 742 | #endif |
f0cbd3ec FB |
743 | return NULL; |
744 | } | |
fdbfba8c | 745 | setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); |
05658ecb | 746 | opt = 1; |
fdbfba8c | 747 | setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int)); |
5fafdf24 | 748 | |
f0cbd3ec | 749 | getsockname(s,(struct sockaddr *)&addr,&addrlen); |
eae303ff | 750 | so->so_ffamily = AF_INET; |
f0cbd3ec FB |
751 | so->so_fport = addr.sin_port; |
752 | if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) | |
460fec67 | 753 | so->so_faddr = slirp->vhost_addr; |
f0cbd3ec FB |
754 | else |
755 | so->so_faddr = addr.sin_addr; | |
756 | ||
757 | so->s = s; | |
758 | return so; | |
759 | } | |
760 | ||
f0cbd3ec FB |
761 | /* |
762 | * Various session state calls | |
763 | * XXX Should be #define's | |
764 | * The socket state stuff needs work, these often get call 2 or 3 | |
765 | * times each when only 1 was needed | |
766 | */ | |
767 | void | |
511d2b14 | 768 | soisfconnecting(struct socket *so) |
f0cbd3ec FB |
769 | { |
770 | so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| | |
771 | SS_FCANTSENDMORE|SS_FWDRAIN); | |
772 | so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ | |
773 | } | |
774 | ||
775 | void | |
511d2b14 | 776 | soisfconnected(struct socket *so) |
f0cbd3ec FB |
777 | { |
778 | so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); | |
779 | so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ | |
780 | } | |
781 | ||
9634d903 BS |
782 | static void |
783 | sofcantrcvmore(struct socket *so) | |
f0cbd3ec FB |
784 | { |
785 | if ((so->so_state & SS_NOFDREF) == 0) { | |
786 | shutdown(so->s,0); | |
f0cbd3ec FB |
787 | } |
788 | so->so_state &= ~(SS_ISFCONNECTING); | |
f932b6ce JK |
789 | if (so->so_state & SS_FCANTSENDMORE) { |
790 | so->so_state &= SS_PERSISTENT_MASK; | |
791 | so->so_state |= SS_NOFDREF; /* Don't select it */ | |
792 | } else { | |
f0cbd3ec | 793 | so->so_state |= SS_FCANTRCVMORE; |
f932b6ce | 794 | } |
f0cbd3ec FB |
795 | } |
796 | ||
9634d903 BS |
797 | static void |
798 | sofcantsendmore(struct socket *so) | |
f0cbd3ec FB |
799 | { |
800 | if ((so->so_state & SS_NOFDREF) == 0) { | |
02d2c54c | 801 | shutdown(so->s,1); /* send FIN to fhost */ |
f0cbd3ec FB |
802 | } |
803 | so->so_state &= ~(SS_ISFCONNECTING); | |
f932b6ce JK |
804 | if (so->so_state & SS_FCANTRCVMORE) { |
805 | so->so_state &= SS_PERSISTENT_MASK; | |
806 | so->so_state |= SS_NOFDREF; /* as above */ | |
807 | } else { | |
f0cbd3ec | 808 | so->so_state |= SS_FCANTSENDMORE; |
f932b6ce | 809 | } |
f0cbd3ec FB |
810 | } |
811 | ||
f0cbd3ec FB |
812 | /* |
813 | * Set write drain mode | |
814 | * Set CANTSENDMORE once all data has been write()n | |
815 | */ | |
816 | void | |
511d2b14 | 817 | sofwdrain(struct socket *so) |
f0cbd3ec FB |
818 | { |
819 | if (so->so_rcv.sb_cc) | |
820 | so->so_state |= SS_FWDRAIN; | |
821 | else | |
822 | sofcantsendmore(so); | |
823 | } | |
5379229a GS |
824 | |
825 | /* | |
826 | * Translate addr in host addr when it is a virtual address | |
827 | */ | |
828 | void sotranslate_out(struct socket *so, struct sockaddr_storage *addr) | |
829 | { | |
830 | Slirp *slirp = so->slirp; | |
831 | struct sockaddr_in *sin = (struct sockaddr_in *)addr; | |
05061d85 | 832 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; |
5379229a GS |
833 | |
834 | switch (addr->ss_family) { | |
835 | case AF_INET: | |
836 | if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == | |
837 | slirp->vnetwork_addr.s_addr) { | |
838 | /* It's an alias */ | |
839 | if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { | |
840 | if (get_dns_addr(&sin->sin_addr) < 0) { | |
841 | sin->sin_addr = loopback_addr; | |
842 | } | |
843 | } else { | |
844 | sin->sin_addr = loopback_addr; | |
845 | } | |
846 | } | |
847 | ||
226ea7a9 | 848 | DEBUG_MISC(" addr.sin_port=%d, addr.sin_addr.s_addr=%.16s", |
2afbb788 | 849 | ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)); |
5379229a GS |
850 | break; |
851 | ||
05061d85 GS |
852 | case AF_INET6: |
853 | if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, | |
854 | slirp->vprefix_len)) { | |
855 | if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) { | |
ef763fa4 ST |
856 | uint32_t scope_id; |
857 | if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) { | |
858 | sin6->sin6_scope_id = scope_id; | |
859 | } else { | |
05061d85 | 860 | sin6->sin6_addr = in6addr_loopback; |
1d17654e | 861 | } |
05061d85 GS |
862 | } else { |
863 | sin6->sin6_addr = in6addr_loopback; | |
864 | } | |
865 | } | |
866 | break; | |
867 | ||
5379229a GS |
868 | default: |
869 | break; | |
870 | } | |
871 | } | |
872 | ||
873 | void sotranslate_in(struct socket *so, struct sockaddr_storage *addr) | |
874 | { | |
875 | Slirp *slirp = so->slirp; | |
876 | struct sockaddr_in *sin = (struct sockaddr_in *)addr; | |
05061d85 | 877 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; |
5379229a GS |
878 | |
879 | switch (addr->ss_family) { | |
880 | case AF_INET: | |
881 | if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == | |
882 | slirp->vnetwork_addr.s_addr) { | |
883 | uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; | |
884 | ||
885 | if ((so->so_faddr.s_addr & inv_mask) == inv_mask) { | |
886 | sin->sin_addr = slirp->vhost_addr; | |
887 | } else if (sin->sin_addr.s_addr == loopback_addr.s_addr || | |
888 | so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { | |
889 | sin->sin_addr = so->so_faddr; | |
890 | } | |
891 | } | |
892 | break; | |
893 | ||
05061d85 GS |
894 | case AF_INET6: |
895 | if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, | |
896 | slirp->vprefix_len)) { | |
897 | if (in6_equal(&sin6->sin6_addr, &in6addr_loopback) | |
898 | || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) { | |
899 | sin6->sin6_addr = so->so_faddr6; | |
900 | } | |
901 | } | |
902 | break; | |
903 | ||
5379229a GS |
904 | default: |
905 | break; | |
906 | } | |
907 | } | |
908 | ||
909 | /* | |
910 | * Translate connections from localhost to the real hostname | |
911 | */ | |
912 | void sotranslate_accept(struct socket *so) | |
913 | { | |
914 | Slirp *slirp = so->slirp; | |
915 | ||
916 | switch (so->so_ffamily) { | |
917 | case AF_INET: | |
918 | if (so->so_faddr.s_addr == INADDR_ANY || | |
919 | (so->so_faddr.s_addr & loopback_mask) == | |
920 | (loopback_addr.s_addr & loopback_mask)) { | |
921 | so->so_faddr = slirp->vhost_addr; | |
922 | } | |
923 | break; | |
924 | ||
05061d85 GS |
925 | case AF_INET6: |
926 | if (in6_equal(&so->so_faddr6, &in6addr_any) || | |
927 | in6_equal(&so->so_faddr6, &in6addr_loopback)) { | |
928 | so->so_faddr6 = slirp->vhost_addr6; | |
929 | } | |
930 | break; | |
931 | ||
5379229a GS |
932 | default: |
933 | break; | |
934 | } | |
935 | } | |
c21d9594 MAL |
936 | |
937 | void sodrop(struct socket *s, int num) | |
938 | { | |
939 | if (sbdrop(&s->so_snd, num)) { | |
3e0fad3a | 940 | s->slirp->cb->notify(s->slirp->opaque); |
c21d9594 MAL |
941 | } |
942 | } |