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