Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/udp.c
2 views
/* SPDX-License-Identifier: BSD-3-Clause */1/*2* Copyright (c) 1982, 1986, 1988, 1990, 19933* The Regents of the University of California. All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13* 3. Neither the name of the University nor the names of its contributors14* may be used to endorse or promote products derived from this software15* without specific prior written permission.16*17* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*29* @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/9430* udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp31*/3233/*34* Changes and additions relating to SLiRP35* Copyright (c) 1995 Danny Gasparovski.36*37* Please read the file COPYRIGHT for the38* terms and conditions of the copyright.39*/4041#include "slirp.h"42#include "ip_icmp.h"4344static uint8_t udp_tos(struct socket *so);4546void udp_init(Slirp *slirp)47{48slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;49slirp->udp_last_so = &slirp->udb;50}5152void udp_cleanup(Slirp *slirp)53{54struct socket *so, *so_next;5556for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {57so_next = so->so_next;58udp_detach(so);59}60}6162/* m->m_data points at ip packet header63* m->m_len length ip packet64* ip->ip_len length data (IPDU)65*/66void udp_input(register struct mbuf *m, int iphlen)67{68Slirp *slirp = m->slirp;69M_DUP_DEBUG(slirp, m, 0, 0);7071register struct ip *ip;72register struct udphdr *uh;73int len;74struct ip save_ip;75struct socket *so;76struct sockaddr_storage lhost;77struct sockaddr_in *lhost4;78int ttl;7980DEBUG_CALL("udp_input");81DEBUG_ARG("m = %p", m);82DEBUG_ARG("iphlen = %d", iphlen);8384/*85* Strip IP options, if any; should skip this,86* make available to user, and use on returned packets,87* but we don't yet have a way to check the checksum88* with options still present.89*/90if (iphlen > sizeof(struct ip)) {91ip_stripoptions(m);92iphlen = sizeof(struct ip);93}9495/*96* Get IP and UDP header together in first mbuf.97*/98ip = mtod_check(m, iphlen + sizeof(struct udphdr));99if (ip == NULL) {100goto bad;101}102uh = (struct udphdr *)((char *)ip + iphlen);103104/*105* Make mbuf data length reflect UDP length.106* If not enough data to reflect UDP length, drop.107*/108len = ntohs((uint16_t)uh->uh_ulen);109110if (ip->ip_len != len) {111if (len > ip->ip_len) {112goto bad;113}114m_adj(m, len - ip->ip_len);115ip->ip_len = len;116}117118/*119* Save a copy of the IP header in case we want restore it120* for sending an ICMP error message in response.121*/122save_ip = *ip;123save_ip.ip_len += iphlen; /* tcp_input subtracts this */124125/*126* Checksum extended UDP header and data.127*/128if (uh->uh_sum) {129memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));130((struct ipovly *)ip)->ih_x1 = 0;131((struct ipovly *)ip)->ih_len = uh->uh_ulen;132if (cksum(m, len + sizeof(struct ip))) {133goto bad;134}135}136137lhost.ss_family = AF_INET;138lhost4 = (struct sockaddr_in *)&lhost;139lhost4->sin_addr = ip->ip_src;140lhost4->sin_port = uh->uh_sport;141142/*143* handle DHCP/BOOTP144*/145if (ntohs(uh->uh_dport) == BOOTP_SERVER &&146(ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||147ip->ip_dst.s_addr == 0xffffffff)) {148bootp_input(m);149goto bad;150}151152/*153* handle TFTP154*/155if (ntohs(uh->uh_dport) == TFTP_SERVER &&156ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {157m->m_data += iphlen;158m->m_len -= iphlen;159tftp_input(&lhost, m);160m->m_data -= iphlen;161m->m_len += iphlen;162goto bad;163}164165if (slirp->restricted) {166goto bad;167}168169/*170* Locate pcb for datagram.171*/172so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);173174if (so == NULL) {175/*176* If there's no socket for this packet,177* create one178*/179so = socreate(slirp, IPPROTO_UDP);180if (udp_attach(so, AF_INET) == -1) {181DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));182sofree(so);183goto bad;184}185186/*187* Setup fields188*/189so->so_lfamily = AF_INET;190so->so_laddr = ip->ip_src;191so->so_lport = uh->uh_sport;192193if ((so->so_iptos = udp_tos(so)) == 0)194so->so_iptos = ip->ip_tos;195196/*197* XXXXX Here, check if it's in udpexec_list,198* and if it is, do the fork_exec() etc.199*/200}201202so->so_ffamily = AF_INET;203so->so_faddr = ip->ip_dst; /* XXX */204so->so_fport = uh->uh_dport; /* XXX */205206iphlen += sizeof(struct udphdr);207m->m_len -= iphlen;208m->m_data += iphlen;209210/*211* Check for TTL212*/213ttl = save_ip.ip_ttl-1;214if (ttl <= 0) {215m->m_len += iphlen;216m->m_data -= iphlen;217*ip = save_ip;218DEBUG_MISC("udp ttl exceeded");219icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, NULL);220goto bad;221}222setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));223224/*225* Now we sendto() the packet.226*/227if (sosendto(so, m) == -1) {228m->m_len += iphlen;229m->m_data -= iphlen;230*ip = save_ip;231DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));232icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));233goto bad;234}235236m_free(so->so_m); /* used for ICMP if error on sorecvfrom */237238/* restore the orig mbuf packet */239m->m_len += iphlen;240m->m_data -= iphlen;241*ip = save_ip;242so->so_m = m; /* ICMP backup */243244return;245bad:246m_free(m);247}248249int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,250struct sockaddr_in *daddr, int iptos)251{252Slirp *slirp = m->slirp;253char addr[INET_ADDRSTRLEN];254255M_DUP_DEBUG(slirp, m, 0, sizeof(struct udpiphdr));256257register struct udpiphdr *ui;258int error = 0;259260DEBUG_CALL("udp_output");261DEBUG_ARG("so = %p", so);262DEBUG_ARG("m = %p", m);263DEBUG_ARG("saddr = %s", inet_ntop(AF_INET, &saddr->sin_addr, addr, sizeof(addr)));264DEBUG_ARG("daddr = %s", inet_ntop(AF_INET, &daddr->sin_addr, addr, sizeof(addr)));265266/*267* Adjust for header268*/269m->m_data -= sizeof(struct udpiphdr);270m->m_len += sizeof(struct udpiphdr);271272/*273* Fill in mbuf with extended UDP header274* and addresses and length put into network format.275*/276ui = mtod(m, struct udpiphdr *);277memset(&ui->ui_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));278ui->ui_x1 = 0;279ui->ui_pr = IPPROTO_UDP;280ui->ui_len = htons(m->m_len - sizeof(struct ip));281/* XXXXX Check for from-one-location sockets, or from-any-location sockets282*/283ui->ui_src = saddr->sin_addr;284ui->ui_dst = daddr->sin_addr;285ui->ui_sport = saddr->sin_port;286ui->ui_dport = daddr->sin_port;287ui->ui_ulen = ui->ui_len;288289/*290* Stuff checksum and output datagram.291*/292ui->ui_sum = 0;293if ((ui->ui_sum = cksum(m, m->m_len)) == 0)294ui->ui_sum = 0xffff;295((struct ip *)ui)->ip_len = m->m_len;296297((struct ip *)ui)->ip_ttl = IPDEFTTL;298((struct ip *)ui)->ip_tos = iptos;299300error = ip_output(so, m);301302return (error);303}304305int udp_attach(struct socket *so, unsigned short af)306{307so->s = slirp_socket(af, SOCK_DGRAM, 0);308if (so->s != -1) {309if (slirp_bind_outbound(so, af) != 0) {310// bind failed - close socket311closesocket(so->s);312so->s = -1;313return -1;314}315316#ifdef __linux__317{318int opt = 1;319switch (af) {320case AF_INET:321setsockopt(so->s, IPPROTO_IP, IP_RECVERR, &opt, sizeof(opt));322break;323case AF_INET6:324setsockopt(so->s, IPPROTO_IPV6, IPV6_RECVERR, &opt, sizeof(opt));325break;326default:327g_assert_not_reached();328}329}330#endif331332so->so_expire = curtime + SO_EXPIRE;333slirp_insque(so, &so->slirp->udb);334}335so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);336return (so->s);337}338339void udp_detach(struct socket *so)340{341so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);342closesocket(so->s);343sofree(so);344}345346static const struct tos_t udptos[] = { { 0, 53, IPTOS_LOWDELAY, 0 }, /* DNS */347{ 0, 0, 0, 0 } };348349static uint8_t udp_tos(struct socket *so)350{351int i = 0;352353while (udptos[i].tos) {354if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||355(udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {356if (so->slirp->enable_emu)357so->so_emu = udptos[i].emu;358return udptos[i].tos;359}360i++;361}362363return 0;364}365366struct socket *udpx_listen(Slirp *slirp,367const struct sockaddr *haddr, socklen_t haddrlen,368const struct sockaddr *laddr, socklen_t laddrlen,369int flags)370{371struct socket *so;372socklen_t addrlen;373int save_errno;374375so = socreate(slirp, IPPROTO_UDP);376so->s = slirp_socket(haddr->sa_family, SOCK_DGRAM, 0);377if (so->s < 0) {378save_errno = errno;379sofree(so);380errno = save_errno;381return NULL;382}383if (haddr->sa_family == AF_INET6)384slirp_socket_set_v6only(so->s, (flags & SS_HOSTFWD_V6ONLY) != 0);385so->so_expire = curtime + SO_EXPIRE;386slirp_insque(so, &slirp->udb);387388if (bind(so->s, haddr, haddrlen) < 0) {389save_errno = errno;390udp_detach(so);391errno = save_errno;392return NULL;393}394slirp_socket_set_fast_reuse(so->s);395396addrlen = sizeof(so->fhost);397getsockname(so->s, &so->fhost.sa, &addrlen);398sotranslate_accept(so);399400sockaddr_copy(&so->lhost.sa, sizeof(so->lhost), laddr, laddrlen);401402if (flags != SS_FACCEPTONCE)403so->so_expire = 0;404so->so_state &= SS_PERSISTENT_MASK;405so->so_state |= SS_ISFCONNECTED | flags;406407return so;408}409410struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,411uint32_t laddr, unsigned lport, int flags)412{413struct sockaddr_in hsa, lsa;414415memset(&hsa, 0, sizeof(hsa));416hsa.sin_family = AF_INET;417hsa.sin_addr.s_addr = haddr;418hsa.sin_port = hport;419420memset(&lsa, 0, sizeof(lsa));421lsa.sin_family = AF_INET;422lsa.sin_addr.s_addr = laddr;423lsa.sin_port = lport;424425return udpx_listen(slirp, (const struct sockaddr *) &hsa, sizeof(hsa), (struct sockaddr *) &lsa, sizeof(lsa), flags);426}427428429