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