udp.c revision c1490f719c97f91d4ca70499df678df22051f763
a89ad754cce3cfc8aee71760e10217b54020360dTripp * Copyright (c) 1982, 1986, 1988, 1990, 1993
a89ad754cce3cfc8aee71760e10217b54020360dTripp * The Regents of the University of California. All rights reserved.
828c58761d90445b8b9d20a82d85dc1479317f71Tripp * Redistribution and use in source and binary forms, with or without
828c58761d90445b8b9d20a82d85dc1479317f71Tripp * modification, are permitted provided that the following conditions
828c58761d90445b8b9d20a82d85dc1479317f71Tripp * 1. Redistributions of source code must retain the above copyright
828c58761d90445b8b9d20a82d85dc1479317f71Tripp * notice, this list of conditions and the following disclaimer.
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp * 2. Redistributions in binary form must reproduce the above copyright
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * notice, this list of conditions and the following disclaimer in the
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * documentation and/or other materials provided with the distribution.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * 3. All advertising materials mentioning features or use of this software
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * must display the following acknowledgement:
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * This product includes software developed by the University of
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * California, Berkeley and its contributors.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * 4. Neither the name of the University nor the names of its contributors
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * may be used to endorse or promote products derived from this software
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * without specific prior written permission.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * SUCH DAMAGE.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Changes and additions relating to SLiRP
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Copyright (c) 1995 Danny Gasparovski.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Please read the file COPYRIGHT for the
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * terms and conditions of the copyright.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * UDP protocol implementation.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Per RFC 768, August, 1980.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp/* m->m_data points at ip packet header
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * m->m_len length ip packet
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * ip->ip_len length data (IPDU)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTrippudp_input(PNATState pData, register struct mbuf *m, int iphlen)
9eaaa502227248d304ac9170902697d02158c1d9Tripp * Strip IP options, if any; should skip this,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * make available to user, and use on returned packets,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * but we don't yet have a way to check the checksum
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * with options still present.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Get IP and UDP header together in first mbuf.
9eaaa502227248d304ac9170902697d02158c1d9Tripp * Make mbuf data length reflect UDP length.
9eaaa502227248d304ac9170902697d02158c1d9Tripp * If not enough data to reflect UDP length, drop.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Save a copy of the IP header in case we want restore it
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * for sending an ICMP error message in response.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Checksum extended UDP header and data.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* keep uh_sum for ICMP reply */
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp * handle TFTP
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Locate pcb for datagram.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * If there's no socket for this packet,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * create one
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp * Setup fields
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp /* udp_last_so = so; */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * XXXXX Here, check if it's in udpexec_list,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * and if it is, do the fork_exec() etc.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Now we sendto() the packet.
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp ret = setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if (ret < 0) {
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp LogRel(("NAT: Error (%s) occurred while setting TTL(%d) attribute of IP packet to socket %R[natsock]\n", strerror(errno), ip->ip_ttl, so));
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp DEBUG_MISC((dfd,"udp tx errno = %d-%s\n", errno, strerror(errno)));
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp icmp_error(pData, m, ICMP_UNREACH,ICMP_UNREACH_NET, 0, strerror(errno));
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp m_free(pData, so->so_m); /* used for ICMP if error on sorecvfrom */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* restore the orig mbuf packet */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTrippint udp_output2(PNATState pData, struct socket *so, struct mbuf *m,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Adjust for header
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Fill in mbuf with extended UDP header
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * and addresses and length put into network format.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Stuff checksum and output datagram.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTrippint udp_output(PNATState pData, struct socket *so, struct mbuf *m,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if ((so->so_faddr.s_addr & htonl(pData->netmask)) == special_addr.s_addr)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if ((so->so_faddr.s_addr & htonl(~pData->netmask)) == htonl(~pData->netmask))
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* Any UDP packet to the loopback address must be translated to be from
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * the forwarding address, i.e. 10.0.2.2. */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp return udp_output2(pData, so, m, &saddr, &daddr, so->so_iptos);
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Here, we bind() the socket. Although not really needed
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * (sendto() on an unbound socket will bind it), it's done
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * here so that emulation of ytalk etc. don't have to do it
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if (bind(so->s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* success, insert in queue */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* enable broadcast for later use */
bbd1285cbb2183b7f89010412ad97ae1680b4b5eTripp setsockopt(so->s, SOL_SOCKET, SO_BROADCAST, (const char *)&opt, sizeof(opt));
bbd1285cbb2183b7f89010412ad97ae1680b4b5eTripp so->so_hlport = ((struct sockaddr_in *)&sa_addr)->sin_port;
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp so->so_hladdr.s_addr = ((struct sockaddr_in *)&sa_addr)->sin_addr.s_addr;
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp return so->s;
bbd1285cbb2183b7f89010412ad97ae1680b4b5eTripp { 0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME }, /* Cu-Seeme */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp { 0, 0, 0, 0 }
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if ( (udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp || (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport))
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Here, talk/ytalk/ntalk requests must be emulated
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTrippudp_emu(PNATState pData, struct socket *so, struct mbuf *m)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Talk emulation. We always change the ctl_addr to get
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * some answers from the daemon. When an ANNOUNCE comes,
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * we send LEAVE_INVITE to the local daemons. Also when a
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * DELETE comes, we send copies to the local daemons.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp } while (0)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp/* old_sockaddr to sockaddr_in */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* old talk */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* new talk */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp return; /* for LOOK_UP this is enough */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* make a copy of the message */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * If if is an ANNOUNCE message, we go through the
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * request table to see if a tcp port has already
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * been redirected for this socket. If not, we solisten()
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * a new socket and add this entry to the table.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * The port number of the tcp socket and our IP
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * are put to the addr field of the message structures.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Then a LEAVE_INVITE is sent to both local daemon
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * ports, 517 and 518. This is why we have two copies
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * of the message, one in old talk and one in new talk
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp break; /* found it */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* no entry for so, create new */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp req = (struct talk_request *)malloc(sizeof(struct talk_request));
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* replace port number in addr field */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp getsockname(req->tcp_so->s, (struct sockaddr *) &addr, &addrlen);
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* send LEAVE_INVITEs */
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * If it is a DELETE message, we send a copy to the
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * local daemons. Then we delete the entry corresponding
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * to our socket from the request table.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp /* delete table entry */
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp * Cu-SeeMe emulation.
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp * Hopefully the packet is more that 16 bytes long. We don't
c7ba96d16d58075a9ab8d5c1e46c6c83ce11cb4eTripp * do any other tests, just replace the address and port
09688ec5ffb8b9cf9883a770e2f9ebd60b28888dTripp if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
struct socket *
return NULL;
return NULL;
/* if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) */
return so;