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 #define SLIRP_COMPILATION 1
48 #include "sockets.h"
49
50 struct udpstat udpstat;
51
52 struct socket udb;
53
54 /*
55 * UDP protocol implementation.
56 * Per RFC 768, August, 1980.
57 */
58 #ifndef COMPAT_42
59 int udpcksum = 1;
60 #else
61 int udpcksum = 0; /* XXX */
62 #endif
63
64 struct socket *udp_last_so = &udb;
65
66 void
udp_init()67 udp_init()
68 {
69 udb.so_next = udb.so_prev = &udb;
70 }
71 /* m->m_data points at ip packet header
72 * m->m_len length ip packet
73 * ip->ip_len length data (IPDU)
74 */
75 void
udp_input(m,iphlen)76 udp_input(m, iphlen)
77 register MBuf m;
78 int iphlen;
79 {
80 register struct ip *ip;
81 register struct udphdr *uh;
82 /* MBuf opts = 0;*/
83 int len;
84 struct ip save_ip;
85 struct socket *so;
86
87 DEBUG_CALL("udp_input");
88 DEBUG_ARG("m = %lx", (long)m);
89 DEBUG_ARG("iphlen = %d", iphlen);
90
91 udpstat.udps_ipackets++;
92
93 /*
94 * Strip IP options, if any; should skip this,
95 * make available to user, and use on returned packets,
96 * but we don't yet have a way to check the checksum
97 * with options still present.
98 */
99 if(iphlen > sizeof(struct ip)) {
100 ip_stripoptions(m, (MBuf )0);
101 iphlen = sizeof(struct ip);
102 }
103
104 /*
105 * Get IP and UDP header together in first mbuf.
106 */
107 ip = MBUF_TO(m, struct ip *);
108 uh = (struct udphdr *)((caddr_t)ip + iphlen);
109
110 /*
111 * Make mbuf data length reflect UDP length.
112 * If not enough data to reflect UDP length, drop.
113 */
114 len = ntohs((u_int16_t)uh->uh_ulen);
115
116 if (ip->ip_len != len) {
117 if (len > ip->ip_len) {
118 udpstat.udps_badlen++;
119 goto bad;
120 }
121 mbuf_trim(m, len - ip->ip_len);
122 ip->ip_len = len;
123 }
124
125 /*
126 * Save a copy of the IP header in case we want restore it
127 * for sending an ICMP error message in response.
128 */
129 save_ip = *ip;
130 save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
131
132 /*
133 * Checksum extended UDP header and data.
134 */
135 if (udpcksum && uh->uh_sum) {
136 memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
137 ((struct ipovly *)ip)->ih_x1 = 0;
138 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
139 /* keep uh_sum for ICMP reply
140 * uh->uh_sum = cksum(m, len + sizeof (struct ip));
141 * if (uh->uh_sum) {
142 */
143 if(cksum(m, len + sizeof(struct ip))) {
144 udpstat.udps_badsum++;
145 goto bad;
146 }
147 }
148
149 /*
150 * handle DHCP/BOOTP
151 */
152 if (port_geth(uh->uh_dport) == BOOTP_SERVER) {
153 bootp_input(m);
154 goto bad;
155 }
156
157 /*
158 * handle TFTP
159 */
160 if (port_geth(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_laddr_port != port_geth(uh->uh_sport) ||
170 so->so_laddr_ip != ip_geth(ip->ip_src)) {
171 struct socket *tmp;
172
173 for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
174 if (tmp->so_laddr_port == port_geth(uh->uh_sport) &&
175 tmp->so_laddr_ip == ip_geth(ip->ip_src)) {
176 tmp->so_faddr_ip = ip_geth(ip->ip_dst);
177 tmp->so_faddr_port = port_geth(uh->uh_dport);
178 so = tmp;
179 break;
180 }
181 }
182 if (tmp == &udb) {
183 so = NULL;
184 } else {
185 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,errno_str));
199 sofree(so);
200 goto bad;
201 }
202
203 /*
204 * Setup fields
205 */
206 /* udp_last_so = so; */
207 so->so_laddr_ip = ip_geth(ip->ip_src);
208 so->so_laddr_port = port_geth(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_geth(ip->ip_dst); /* XXX */
220 so->so_faddr_port = port_geth(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, errno_str));
237 icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,errno_str);
238 }
239
240 mbuf_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 mbuf_free(m);
251 /* if (opts) mbuf_free(opts); */
252 return;
253 }
254
udp_output2_(struct socket * so,MBuf m,const SockAddress * saddr,const SockAddress * daddr,int iptos)255 int udp_output2_(struct socket* so, MBuf m,
256 const SockAddress* saddr,
257 const SockAddress* daddr,
258 int iptos)
259 {
260 register struct udpiphdr *ui;
261 uint32_t saddr_ip = sock_address_get_ip(saddr);
262 uint32_t daddr_ip = sock_address_get_ip(daddr);
263 int saddr_port = sock_address_get_port(saddr);
264 int daddr_port = sock_address_get_port(daddr);
265 int error = 0;
266
267 DEBUG_CALL("udp_output");
268 DEBUG_ARG("so = %lx", (long)so);
269 DEBUG_ARG("m = %lx", (long)m);
270 DEBUG_ARG("saddr = %lx", (long) saddr_ip);
271 DEBUG_ARG("daddr = %lx", (long) daddr_ip);
272
273 /*
274 * Adjust for header
275 */
276 m->m_data -= sizeof(struct udpiphdr);
277 m->m_len += sizeof(struct udpiphdr);
278
279 /*
280 * Fill in mbuf with extended UDP header
281 * and addresses and length put into network format.
282 */
283 ui = MBUF_TO(m, struct udpiphdr *);
284 memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
285 ui->ui_x1 = 0;
286 ui->ui_pr = IPPROTO_UDP;
287 ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
288 /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
289 ui->ui_src = ip_seth(saddr_ip);
290 ui->ui_dst = ip_seth(daddr_ip);
291 ui->ui_sport = port_seth(saddr_port);
292 ui->ui_dport = port_seth(daddr_port);
293 ui->ui_ulen = ui->ui_len;
294
295 /*
296 * Stuff checksum and output datagram.
297 */
298 ui->ui_sum = 0;
299 if (udpcksum) {
300 if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
301 ui->ui_sum = 0xffff;
302 }
303 ((struct ip *)ui)->ip_len = m->m_len;
304
305 ((struct ip *)ui)->ip_ttl = ip_defttl;
306 ((struct ip *)ui)->ip_tos = iptos;
307
308 udpstat.udps_opackets++;
309
310 error = ip_output(so, m);
311
312 return (error);
313 }
314
udp_output_(struct socket * so,MBuf m,SockAddress * from)315 int udp_output_(struct socket *so, MBuf m, SockAddress* from)
316 {
317 SockAddress saddr, daddr;
318 uint32_t saddr_ip;
319 uint16_t saddr_port;
320
321 saddr_ip = sock_address_get_ip(from);
322 saddr_port = sock_address_get_port(from);
323
324 if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
325 saddr_ip = so->so_faddr_ip;
326 if ((so->so_faddr_ip & 0x000000ff) == 0xff)
327 saddr_ip = alias_addr_ip;
328 }
329
330 sock_address_init_inet( &saddr, saddr_ip, saddr_port );
331 sock_address_init_inet( &daddr, so->so_laddr_ip, so->so_laddr_port );
332
333 return udp_output2_(so, m, &saddr, &daddr, so->so_iptos);
334 }
335
336 int
udp_attach(so)337 udp_attach(so)
338 struct socket *so;
339 {
340 so->s = socket_anyaddr_server( 0, SOCKET_DGRAM );
341 if (so->s != -1) {
342 /* success, insert in queue */
343 so->so_expire = curtime + SO_EXPIRE;
344 insque(so,&udb);
345 }
346 return(so->s);
347 }
348
349 void
udp_detach(so)350 udp_detach(so)
351 struct socket *so;
352 {
353 socket_close(so->s);
354 /* if (so->so_m) mbuf_free(so->so_m); done by sofree */
355
356 sofree(so);
357 }
358
359 struct tos_t udptos[] = {
360 {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
361 {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */
362 {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */
363 {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
364 {0, 0, 0, 0}
365 };
366
367 u_int8_t
udp_tos(so)368 udp_tos(so)
369 struct socket *so;
370 {
371 int i = 0;
372
373 while(udptos[i].tos) {
374 if ((udptos[i].fport && so->so_faddr_port == udptos[i].fport) ||
375 (udptos[i].lport && so->so_laddr_port == udptos[i].lport)) {
376 so->so_emu = udptos[i].emu;
377 return udptos[i].tos;
378 }
379 i++;
380 }
381
382 return 0;
383 }
384
385 /*
386 * Here, talk/ytalk/ntalk requests must be emulated
387 */
388 void
udp_emu(so,m)389 udp_emu(so, m)
390 struct socket *so;
391 MBuf m;
392 {
393 SockAddress sockaddr;
394
395 struct cu_header {
396 uint16_t d_family; // destination family
397 uint16_t d_port; // destination port
398 uint32_t d_addr; // destination address
399 uint16_t s_family; // source family
400 uint16_t s_port; // source port
401 uint32_t so_addr; // source address
402 uint32_t seqn; // sequence number
403 uint16_t message; // message
404 uint16_t data_type; // data type
405 uint16_t pkt_len; // packet length
406 } *cu_head;
407
408 switch(so->so_emu) {
409
410 case EMU_CUSEEME:
411
412 /*
413 * Cu-SeeMe emulation.
414 * Hopefully the packet is more that 16 bytes long. We don't
415 * do any other tests, just replace the address and port
416 * fields.
417 */
418 if (m->m_len >= sizeof (*cu_head)) {
419 if (socket_get_address(so->s, &sockaddr) < 0)
420 return;
421
422 cu_head = MBUF_TO(m, struct cu_header *);
423 cu_head->s_port = htons( sock_address_get_port(&sockaddr));
424 cu_head->so_addr = htonl( sock_address_get_ip(&sockaddr));
425 }
426
427 return;
428 }
429 }
430
431 struct socket *
udp_listen(port,laddr,lport,flags)432 udp_listen(port, laddr, lport, flags)
433 u_int port;
434 u_int32_t laddr;
435 u_int lport;
436 int flags;
437 {
438 struct socket *so;
439 SockAddress addr;
440 uint32_t addr_ip;
441
442 if ((so = socreate()) == NULL) {
443 free(so);
444 return NULL;
445 }
446 so->s = socket_anyaddr_server( port, SOCKET_DGRAM );
447 so->so_expire = curtime + SO_EXPIRE;
448 so->so_haddr_port = port;
449 insque(so,&udb);
450
451 if (so->s < 0) {
452 udp_detach(so);
453 return NULL;
454 }
455
456 socket_get_address(so->s, &addr);
457
458 so->so_faddr_port = sock_address_get_port(&addr);
459 addr_ip = sock_address_get_ip(&addr);
460
461 if (addr_ip == 0 || addr_ip == loopback_addr_ip)
462 so->so_faddr_ip = alias_addr_ip;
463 else
464 so->so_faddr_ip = addr_ip;
465
466 so->so_laddr_port = lport;
467 so->so_laddr_ip = laddr;
468 if (flags != SS_FACCEPTONCE)
469 so->so_expire = 0;
470
471 so->so_state = SS_ISFCONNECTED;
472
473 return so;
474 }
475
udp_unlisten(u_int port)476 int udp_unlisten (u_int port)
477 {
478 struct socket *so;
479
480 for (so = udb.so_next; so != &udb; so = so->so_next) {
481 if (so->so_haddr_port == port) {
482 break;
483 }
484 }
485
486 if (so == &udb)
487 return -1;
488
489 sofcantrcvmore( so );
490 sofcantsendmore( so );
491 socket_close( so->s );
492 so->s = -1;
493 sofree( so );
494 return 0;
495 }
496