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