VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/udp.c@ 15435

Last change on this file since 15435 was 15355, checked in by vboxsync, 16 years ago

slirp:icmp: enabling UDP traceroute on Unix

  • Property svn:eol-style set to native
File size: 22.5 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
34 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
35 */
36
37/*
38 * Changes and additions relating to SLiRP
39 * Copyright (c) 1995 Danny Gasparovski.
40 *
41 * Please read the file COPYRIGHT for the
42 * terms and conditions of the copyright.
43 */
44
45#include <slirp.h>
46#include "ip_icmp.h"
47
48
49/*
50 * UDP protocol implementation.
51 * Per RFC 768, August, 1980.
52 */
53#define udpcksum 1
54
55void
56udp_init(PNATState pData)
57{
58 udp_last_so = &udb;
59 udb.so_next = udb.so_prev = &udb;
60}
61
62/* m->m_data points at ip packet header
63 * m->m_len length ip packet
64 * ip->ip_len length data (IPDU)
65 */
66void
67udp_input(PNATState pData, register struct mbuf *m, int iphlen)
68{
69 register struct ip *ip;
70 register struct udphdr *uh;
71 int len;
72 struct ip save_ip;
73 struct socket *so;
74#ifdef VBOX_WITH_SLIRP_ICMP
75 int ret;
76#endif
77
78 DEBUG_CALL("udp_input");
79 DEBUG_ARG("m = %lx", (long)m);
80 DEBUG_ARG("iphlen = %d", iphlen);
81
82 udpstat.udps_ipackets++;
83
84 /*
85 * Strip IP options, if any; should skip this,
86 * make available to user, and use on returned packets,
87 * but we don't yet have a way to check the checksum
88 * with options still present.
89 */
90 if (iphlen > sizeof(struct ip))
91 {
92 ip_stripoptions(m, (struct mbuf *)0);
93 iphlen = sizeof(struct ip);
94 }
95
96 /*
97 * Get IP and UDP header together in first mbuf.
98 */
99 ip = mtod(m, struct ip *);
100 uh = (struct udphdr *)((caddr_t)ip + iphlen);
101
102 /*
103 * Make mbuf data length reflect UDP length.
104 * If not enough data to reflect UDP length, drop.
105 */
106 len = ntohs((u_int16_t)uh->uh_ulen);
107
108 if (ip->ip_len != len)
109 {
110 if (len > ip->ip_len)
111 {
112 udpstat.udps_badlen++;
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 (udpcksum && uh->uh_sum)
130 {
131#if !defined(VBOX_WITH_BSD_REASS)
132 ((struct ipovly *)ip)->ih_next = 0;
133 ((struct ipovly *)ip)->ih_prev = 0;
134 ((struct ipovly *)ip)->ih_x1 = 0;
135#else
136 memset(((struct ipovly *)ip)->ih_x1, 0, 9);
137#endif
138 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
139#if 0
140 /* keep uh_sum for ICMP reply */
141 uh->uh_sum = cksum(m, len + sizeof (struct ip));
142 if (uh->uh_sum)
143 {
144
145#endif
146 if(cksum(m, len + sizeof(struct ip)))
147 {
148 udpstat.udps_badsum++;
149 goto bad;
150 }
151 }
152#if 0
153 }
154#endif
155
156 /*
157 * handle DHCP/BOOTP
158 */
159 if (ntohs(uh->uh_dport) == BOOTP_SERVER)
160 {
161 bootp_input(pData, m);
162 goto bad;
163 }
164
165 /*
166 * handle TFTP
167 */
168 if (ntohs(uh->uh_dport) == TFTP_SERVER)
169 {
170 tftp_input(pData, m);
171 goto bad;
172 }
173
174 /*
175 * Locate pcb for datagram.
176 */
177 so = udp_last_so;
178 if ( so->so_lport != uh->uh_sport
179 || so->so_laddr.s_addr != ip->ip_src.s_addr)
180 {
181 struct socket *tmp;
182
183 for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next)
184 {
185 if ( tmp->so_lport == uh->uh_sport
186 && tmp->so_laddr.s_addr == ip->ip_src.s_addr)
187 {
188 so = tmp;
189 break;
190 }
191 }
192 if (tmp == &udb)
193 so = NULL;
194 else
195 {
196 udpstat.udpps_pcbcachemiss++;
197 udp_last_so = so;
198 }
199 }
200
201 if (so == NULL)
202 {
203 /*
204 * If there's no socket for this packet,
205 * create one
206 */
207 if ((so = socreate()) == NULL)
208 goto bad;
209 if (udp_attach(pData, so) == -1)
210 {
211 DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
212 errno,strerror(errno)));
213 sofree(pData, so);
214 goto bad;
215 }
216
217 /*
218 * Setup fields
219 */
220 /* udp_last_so = so; */
221 so->so_laddr = ip->ip_src;
222 so->so_lport = uh->uh_sport;
223
224 if ((so->so_iptos = udp_tos(so)) == 0)
225 so->so_iptos = ip->ip_tos;
226
227 /*
228 * XXXXX Here, check if it's in udpexec_list,
229 * and if it is, do the fork_exec() etc.
230 */
231 }
232
233 so->so_faddr = ip->ip_dst; /* XXX */
234 so->so_fport = uh->uh_dport; /* XXX */
235
236 iphlen += sizeof(struct udphdr);
237 m->m_len -= iphlen;
238 m->m_data += iphlen;
239
240 /*
241 * Now we sendto() the packet.
242 */
243 if (so->so_emu)
244 udp_emu(pData, so, m);
245
246#ifdef VBOX_WITH_SLIRP_ICMP
247 ip->ip_ttl = save_ip.ip_ttl;
248 ret = setsockopt(so->s, IPPROTO_IP, IP_TTL, (void *)&ip->ip_ttl, sizeof(ip->ip_ttl));
249 if (ret < 0) {
250 LogRel(("NAT: Error (%s) occurred while setting TTL(%d) attribute of IP packet to socket %R[natsock]\n", strerror(errno), ip->ip_ttl, so));
251 }
252#endif
253 if(sosendto(pData, so,m) == -1)
254 {
255 m->m_len += iphlen;
256 m->m_data -= iphlen;
257 *ip = save_ip;
258 DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
259 icmp_error(pData, m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
260 }
261
262 m_free(pData, so->so_m); /* used for ICMP if error on sorecvfrom */
263
264 /* restore the orig mbuf packet */
265 m->m_len += iphlen;
266 m->m_data -= iphlen;
267 *ip = save_ip;
268 so->so_m = m; /* ICMP backup */
269
270 return;
271
272bad:
273 m_freem(pData, m);
274 return;
275}
276
277int udp_output2(PNATState pData, struct socket *so, struct mbuf *m,
278 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
279 int iptos)
280{
281 register struct udpiphdr *ui;
282 int error = 0;
283
284 DEBUG_CALL("udp_output");
285 DEBUG_ARG("so = %lx", (long)so);
286 DEBUG_ARG("m = %lx", (long)m);
287 DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
288 DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
289
290 /*
291 * Adjust for header
292 */
293 m->m_data -= sizeof(struct udpiphdr);
294 m->m_len += sizeof(struct udpiphdr);
295
296 /*
297 * Fill in mbuf with extended UDP header
298 * and addresses and length put into network format.
299 */
300 ui = mtod(m, struct udpiphdr *);
301#if !defined(VBOX_WITH_BSD_REASS)
302 ui->ui_next = ui->ui_prev = 0;
303 ui->ui_x1 = 0;
304#else
305 memset(ui->ui_x1, 0, 9);
306#endif
307 ui->ui_pr = IPPROTO_UDP;
308 ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
309 /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
310 ui->ui_src = saddr->sin_addr;
311 ui->ui_dst = daddr->sin_addr;
312 ui->ui_sport = saddr->sin_port;
313 ui->ui_dport = daddr->sin_port;
314 ui->ui_ulen = ui->ui_len;
315
316 /*
317 * Stuff checksum and output datagram.
318 */
319 ui->ui_sum = 0;
320 if (udpcksum)
321 {
322 if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
323 ui->ui_sum = 0xffff;
324 }
325 ((struct ip *)ui)->ip_len = m->m_len;
326 ((struct ip *)ui)->ip_ttl = ip_defttl;
327 ((struct ip *)ui)->ip_tos = iptos;
328
329 udpstat.udps_opackets++;
330
331 error = ip_output(pData, so, m);
332
333 return error;
334}
335
336int udp_output(PNATState pData, struct socket *so, struct mbuf *m,
337 struct sockaddr_in *addr)
338{
339 struct sockaddr_in saddr, daddr;
340
341 saddr = *addr;
342 if ((so->so_faddr.s_addr & htonl(pData->netmask)) == special_addr.s_addr)
343 {
344 saddr.sin_addr.s_addr = so->so_faddr.s_addr;
345 if ((so->so_faddr.s_addr & htonl(~pData->netmask)) == htonl(~pData->netmask))
346 saddr.sin_addr.s_addr = alias_addr.s_addr;
347 }
348
349 /* Any UDP packet to the loopback address must be translated to be from
350 * the forwarding address, i.e. 10.0.2.2. */
351 if ( (saddr.sin_addr.s_addr & htonl(IN_CLASSA_NET))
352 == htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
353 saddr.sin_addr.s_addr = alias_addr.s_addr;
354
355 daddr.sin_addr = so->so_laddr;
356 daddr.sin_port = so->so_lport;
357
358 return udp_output2(pData, so, m, &saddr, &daddr, so->so_iptos);
359}
360
361int
362udp_attach(PNATState pData, struct socket *so)
363{
364 struct sockaddr_in addr;
365#ifdef VBOX_WITH_SLIRP_ICMP
366 struct sockaddr sa_addr;
367 socklen_t socklen = sizeof(struct sockaddr);
368 int status;
369#endif
370
371 if ((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1)
372 {
373 /*
374 * Here, we bind() the socket. Although not really needed
375 * (sendto() on an unbound socket will bind it), it's done
376 * here so that emulation of ytalk etc. don't have to do it
377 */
378 addr.sin_family = AF_INET;
379 addr.sin_port = 0;
380 addr.sin_addr.s_addr = INADDR_ANY;
381 if (bind(so->s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
382 {
383 int lasterrno = errno;
384 closesocket(so->s);
385 so->s = -1;
386#ifdef RT_OS_WINDOWS
387 WSASetLastError(lasterrno);
388#else
389 errno = lasterrno;
390#endif
391 }
392 else
393 {
394 int opt = 1;
395 /* success, insert in queue */
396 so->so_expire = curtime + SO_EXPIRE;
397 /* enable broadcast for later use */
398 setsockopt(so->s, SOL_SOCKET, SO_BROADCAST, (const char *)&opt, sizeof(opt));
399 insque(pData, so,&udb);
400#ifdef VBOX_WITH_SLIRP_ICMP
401 status = getsockname(so->s, &sa_addr, &socklen);
402 Assert(status == 0 && sa_addr.sa_family == AF_INET);
403 so->so_hlport = ((struct sockaddr_in *)&sa_addr)->sin_port;
404 so->so_hladdr.s_addr = ((struct sockaddr_in *)&sa_addr)->sin_addr.s_addr;
405#endif
406 }
407 }
408 return so->s;
409}
410
411void
412udp_detach(PNATState pData, struct socket *so)
413{
414#ifndef VBOX_WITH_SLIRP_ICMP
415 closesocket(so->s);
416 sofree(pData, so);
417#else /*! VBOX_WITH_SLIRP_ICMP */
418 if (so != &pData->icmp_socket)
419 {
420 closesocket(so->s);
421 sofree(pData, so);
422 }
423#endif /* VBOX_WITH_SLIRP_ICMP */
424}
425
426static const struct tos_t udptos[] =
427{
428 { 0, 53, IPTOS_LOWDELAY, 0 }, /* DNS */
429 { 517, 517, IPTOS_LOWDELAY, EMU_TALK }, /* talk */
430 { 518, 518, IPTOS_LOWDELAY, EMU_NTALK }, /* ntalk */
431 { 0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME }, /* Cu-Seeme */
432 { 0, 0, 0, 0 }
433};
434
435u_int8_t
436udp_tos(struct socket *so)
437{
438 int i = 0;
439
440 while(udptos[i].tos)
441 {
442 if ( (udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport)
443 || (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport))
444 {
445 so->so_emu = udptos[i].emu;
446 return udptos[i].tos;
447 }
448 i++;
449 }
450
451 return 0;
452}
453
454#ifdef EMULATE_TALK
455#include "talkd.h"
456#endif
457
458/*
459 * Here, talk/ytalk/ntalk requests must be emulated
460 */
461void
462udp_emu(PNATState pData, struct socket *so, struct mbuf *m)
463{
464 struct sockaddr_in addr;
465 socklen_t addrlen = sizeof(addr);
466#ifdef EMULATE_TALK
467 CTL_MSG_OLD *omsg;
468 CTL_MSG *nmsg;
469 char buff[sizeof(CTL_MSG)];
470 u_char type;
471
472 struct talk_request
473 {
474 struct talk_request *next;
475 struct socket *udp_so;
476 struct socket *tcp_so;
477 } *req;
478
479 static struct talk_request *req_tbl = 0;
480
481#endif
482
483 struct cu_header
484 {
485 uint16_t d_family; /* destination family */
486 uint16_t d_port; /* destination port */
487 uint32_t d_addr; /* destination address */
488 uint16_t s_family; /* source family */
489 uint16_t s_port; /* source port */
490 uint32_t so_addr; /* source address */
491 uint32_t seqn; /* sequence number */
492 uint16_t message; /* message */
493 uint16_t data_type; /* data type */
494 uint16_t pkt_len; /* packet length */
495 } *cu_head;
496
497 switch(so->so_emu)
498 {
499#ifdef EMULATE_TALK
500 case EMU_TALK:
501 case EMU_NTALK:
502 /*
503 * Talk emulation. We always change the ctl_addr to get
504 * some answers from the daemon. When an ANNOUNCE comes,
505 * we send LEAVE_INVITE to the local daemons. Also when a
506 * DELETE comes, we send copies to the local daemons.
507 */
508 if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
509 return;
510
511#define IS_OLD (so->so_emu == EMU_TALK)
512
513#define COPY_MSG(dest, src) \
514 do { \
515 dest->type = src->type; \
516 dest->id_num = src->id_num; \
517 dest->pid = src->pid; \
518 dest->addr = src->addr; \
519 dest->ctl_addr = src->ctl_addr; \
520 memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
521 memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
522 memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE);
523 } while (0)
524
525#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
526/* old_sockaddr to sockaddr_in */
527
528
529 if (IS_OLD)
530 {
531 /* old talk */
532 omsg = mtod(m, CTL_MSG_OLD*);
533 nmsg = (CTL_MSG *) buff;
534 type = omsg->type;
535 OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
536 OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
537 strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD);
538 }
539 else
540 {
541 /* new talk */
542 omsg = (CTL_MSG_OLD *) buff;
543 nmsg = mtod(m, CTL_MSG *);
544 type = nmsg->type;
545 OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
546 OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
547 strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD);
548 }
549
550 if (type == LOOK_UP)
551 return; /* for LOOK_UP this is enough */
552
553 if (IS_OLD)
554 {
555 /* make a copy of the message */
556 COPY_MSG(nmsg, omsg);
557 nmsg->vers = 1;
558 nmsg->answer = 0;
559 }
560 else
561 COPY_MSG(omsg, nmsg);
562
563 /*
564 * If if is an ANNOUNCE message, we go through the
565 * request table to see if a tcp port has already
566 * been redirected for this socket. If not, we solisten()
567 * a new socket and add this entry to the table.
568 * The port number of the tcp socket and our IP
569 * are put to the addr field of the message structures.
570 * Then a LEAVE_INVITE is sent to both local daemon
571 * ports, 517 and 518. This is why we have two copies
572 * of the message, one in old talk and one in new talk
573 * format.
574 */
575
576 if (type == ANNOUNCE)
577 {
578 int s;
579 u_short temp_port;
580
581 for(req = req_tbl; req; req = req->next)
582 if (so == req->udp_so)
583 break; /* found it */
584
585 if (!req)
586 {
587 /* no entry for so, create new */
588 req = (struct talk_request *)malloc(sizeof(struct talk_request));
589 req->udp_so = so;
590 req->tcp_so = solisten(0,
591 OTOSIN(omsg, addr)->sin_addr.s_addr,
592 OTOSIN(omsg, addr)->sin_port,
593 SS_FACCEPTONCE);
594 req->next = req_tbl;
595 req_tbl = req;
596 }
597
598 /* replace port number in addr field */
599 addrlen = sizeof(addr);
600 getsockname(req->tcp_so->s, (struct sockaddr *) &addr, &addrlen);
601 OTOSIN(omsg, addr)->sin_port = addr.sin_port;
602 OTOSIN(omsg, addr)->sin_addr = our_addr;
603 OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
604 OTOSIN(nmsg, addr)->sin_addr = our_addr;
605
606 /* send LEAVE_INVITEs */
607 temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
608 OTOSIN(omsg, ctl_addr)->sin_port = 0;
609 OTOSIN(nmsg, ctl_addr)->sin_port = 0;
610 omsg->type = nmsg->type = LEAVE_INVITE;
611
612 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
613 addr.sin_addr = our_addr;
614 addr.sin_family = AF_INET;
615 addr.sin_port = htons(517);
616 sendto(s, (char *)omsg, sizeof(*omsg), 0,
617 (struct sockaddr *)&addr, sizeof(addr));
618 addr.sin_port = htons(518);
619 sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
620 (struct sockaddr *) &addr, sizeof(addr));
621 closesocket(s) ;
622
623 omsg->type = nmsg->type = ANNOUNCE;
624 OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
625 OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
626 }
627
628 /*
629 * If it is a DELETE message, we send a copy to the
630 * local daemons. Then we delete the entry corresponding
631 * to our socket from the request table.
632 */
633
634 if (type == DELETE)
635 {
636 struct talk_request *temp_req, *req_next;
637 int s;
638 u_short temp_port;
639
640 temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
641 OTOSIN(omsg, ctl_addr)->sin_port = 0;
642 OTOSIN(nmsg, ctl_addr)->sin_port = 0;
643
644 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
645 addr.sin_addr = our_addr;
646 addr.sin_family = AF_INET;
647 addr.sin_port = htons(517);
648 sendto(s, (char *)omsg, sizeof(*omsg), 0,
649 (struct sockaddr *)&addr, sizeof(addr));
650 addr.sin_port = htons(518);
651 sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
652 (struct sockaddr *)&addr, sizeof(addr));
653 closesocket(s);
654
655 OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
656 OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
657
658 /* delete table entry */
659 if (so == req_tbl->udp_so)
660 {
661 temp_req = req_tbl;
662 req_tbl = req_tbl->next;
663 free(temp_req);
664 }
665 else
666 {
667 temp_req = req_tbl;
668 for (req = req_tbl->next; req; req = req_next)
669 {
670 req_next = req->next;
671 if (so == req->udp_so)
672 {
673 temp_req->next = req_next;
674 free(req);
675 break;
676 }
677 else
678 temp_req = req;
679 }
680 }
681 }
682
683 return;
684#endif
685
686 case EMU_CUSEEME:
687 /*
688 * Cu-SeeMe emulation.
689 * Hopefully the packet is more that 16 bytes long. We don't
690 * do any other tests, just replace the address and port
691 * fields.
692 */
693 if (m->m_len >= sizeof (*cu_head))
694 {
695 if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
696 return;
697 cu_head = mtod(m, struct cu_header *);
698 cu_head->s_port = addr.sin_port;
699 cu_head->so_addr = our_addr.s_addr;
700 }
701 return;
702 }
703}
704
705struct socket *
706udp_listen(PNATState pData, u_int port, u_int32_t laddr, u_int lport, int flags)
707{
708 struct sockaddr_in addr;
709 struct socket *so;
710 socklen_t addrlen = sizeof(struct sockaddr_in);
711 int opt = 1;
712
713 if ((so = socreate()) == NULL)
714 {
715 free(so);
716 return NULL;
717 }
718 so->s = socket(AF_INET,SOCK_DGRAM,0);
719 so->so_expire = curtime + SO_EXPIRE;
720 insque(pData, so,&udb);
721
722 addr.sin_family = AF_INET;
723 addr.sin_addr.s_addr = INADDR_ANY;
724 addr.sin_port = port;
725
726 if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0)
727 {
728 udp_detach(pData, so);
729 return NULL;
730 }
731 setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
732/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
733
734 getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
735 so->so_fport = addr.sin_port;
736 /* The original check was completely broken, as the commented out
737 * if statement was always true (INADDR_ANY=0). */
738 /* if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) */
739 if (1 == 0) /* always use the else part */
740 so->so_faddr = alias_addr;
741 else
742 so->so_faddr = addr.sin_addr;
743
744 so->so_lport = lport;
745 so->so_laddr.s_addr = laddr;
746 if (flags != SS_FACCEPTONCE)
747 so->so_expire = 0;
748
749 so->so_state = SS_ISFCONNECTED;
750
751 return so;
752}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette