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