raw_ip.c revision 130281
138032Speter/* 264562Sgshapiro * Copyright (c) 1982, 1986, 1988, 1993 338032Speter * The Regents of the University of California. All rights reserved. 490792Sgshapiro * 590792Sgshapiro * Redistribution and use in source and binary forms, with or without 690792Sgshapiro * modification, are permitted provided that the following conditions 790792Sgshapiro * are met: 838032Speter * 1. Redistributions of source code must retain the above copyright 990792Sgshapiro * notice, this list of conditions and the following disclaimer. 1090792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright 1190792Sgshapiro * notice, this list of conditions and the following disclaimer in the 1290792Sgshapiro * documentation and/or other materials provided with the distribution. 1338032Speter * 4. Neither the name of the University nor the names of its contributors 1490792Sgshapiro * may be used to endorse or promote products derived from this software 1538032Speter * without specific prior written permission. 1690792Sgshapiro * 1790792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1890792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1990792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2090792Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2190792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2290792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2390792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2490792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2590792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2690792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2790792Sgshapiro * SUCH DAMAGE. 2890792Sgshapiro * 2990792Sgshapiro * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 3090792Sgshapiro * $FreeBSD: head/sys/netinet/raw_ip.c 130281 2004-06-09 20:10:38Z ru $ 31132943Sgshapiro */ 3290792Sgshapiro 3390792Sgshapiro#include "opt_inet6.h" 3490792Sgshapiro#include "opt_ipsec.h" 3590792Sgshapiro#include "opt_mac.h" 3690792Sgshapiro#include "opt_random_ip_id.h" 3790792Sgshapiro 3890792Sgshapiro#include <sys/param.h> 3990792Sgshapiro#include <sys/jail.h> 4090792Sgshapiro#include <sys/kernel.h> 4190792Sgshapiro#include <sys/lock.h> 4290792Sgshapiro#include <sys/mac.h> 4390792Sgshapiro#include <sys/malloc.h> 4490792Sgshapiro#include <sys/mbuf.h> 4590792Sgshapiro#include <sys/proc.h> 4690792Sgshapiro#include <sys/protosw.h> 4790792Sgshapiro#include <sys/signalvar.h> 4890792Sgshapiro#include <sys/socket.h> 4938032Speter#include <sys/socketvar.h> 5090792Sgshapiro#include <sys/sx.h> 5138032Speter#include <sys/sysctl.h> 5238032Speter#include <sys/systm.h> 5338032Speter 5438032Speter#include <vm/uma.h> 5538032Speter 5638032Speter#include <net/if.h> 5738032Speter#include <net/route.h> 5838032Speter 5938032Speter#include <netinet/in.h> 6038032Speter#include <netinet/in_systm.h> 6164562Sgshapiro#include <netinet/in_pcb.h> 6264562Sgshapiro#include <netinet/in_var.h> 6364562Sgshapiro#include <netinet/ip.h> 6464562Sgshapiro#include <netinet/ip_var.h> 6564562Sgshapiro#include <netinet/ip_mroute.h> 6638032Speter 6738032Speter#include <netinet/ip_fw.h> 6838032Speter#include <netinet/ip_dummynet.h> 6938032Speter 7038032Speter#ifdef FAST_IPSEC 7138032Speter#include <netipsec/ipsec.h> 7238032Speter#endif /*FAST_IPSEC*/ 7338032Speter 7438032Speter#ifdef IPSEC 7538032Speter#include <netinet6/ipsec.h> 7638032Speter#endif /*IPSEC*/ 7738032Speter 7838032Speterstruct inpcbhead ripcb; 7938032Speterstruct inpcbinfo ripcbinfo; 80261363Sgshapiro 8164562Sgshapiro/* control hooks for ipfw and dummynet */ 8238032Speterip_fw_ctl_t *ip_fw_ctl_ptr; 8338032Speterip_dn_ctl_t *ip_dn_ctl_ptr; 8438032Speter 8538032Speter/* 8638032Speter * hooks for multicast routing. They all default to NULL, 8738032Speter * so leave them not initialized and rely on BSS being set to 0. 8838032Speter */ 8938032Speter 9038032Speter/* The socket used to communicate with the multicast routing daemon. */ 9138032Speterstruct socket *ip_mrouter; 9238032Speter 9338032Speter/* The various mrouter and rsvp functions */ 9438032Speterint (*ip_mrouter_set)(struct socket *, struct sockopt *); 9538032Speterint (*ip_mrouter_get)(struct socket *, struct sockopt *); 9638032Speterint (*ip_mrouter_done)(void); 9738032Speterint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 9838032Speter struct ip_moptions *); 9938032Speterint (*mrt_ioctl)(int, caddr_t); 10038032Speterint (*legal_vif_num)(int); 10138032Speteru_long (*ip_mcast_src)(int); 10238032Speter 10338032Spetervoid (*rsvp_input_p)(struct mbuf *m, int off); 10464562Sgshapiroint (*ip_rsvp_vif)(struct socket *, struct sockopt *); 10538032Spetervoid (*ip_rsvp_force_done)(struct socket *); 10638032Speter 10738032Speter/* 10838032Speter * Nominal space allocated to a raw ip socket. 10938032Speter */ 11064562Sgshapiro#define RIPSNDQ 8192 11138032Speter#define RIPRCVQ 8192 11238032Speter 11338032Speter/* 11464562Sgshapiro * Raw interface to IP protocol. 11538032Speter */ 11638032Speter 11738032Speter/* 11838032Speter * Initialize raw connection block q. 11938032Speter */ 12038032Spetervoid 12138032Speterrip_init() 12264562Sgshapiro{ 12338032Speter INP_INFO_LOCK_INIT(&ripcbinfo, "rip"); 12438032Speter LIST_INIT(&ripcb); 12564562Sgshapiro ripcbinfo.listhead = &ripcb; 12638032Speter /* 12738032Speter * XXX We don't use the hash list for raw IP, but it's easier 12838032Speter * to allocate a one entry hash list than it is to check all 12964562Sgshapiro * over the place for hashbase == NULL. 13064562Sgshapiro */ 13138032Speter ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask); 13290792Sgshapiro ripcbinfo.porthashbase = hashinit(1, M_PCB, &ripcbinfo.porthashmask); 13390792Sgshapiro ripcbinfo.ipi_zone = uma_zcreate("ripcb", sizeof(struct inpcb), 134132943Sgshapiro NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); 135132943Sgshapiro uma_zone_set_max(ripcbinfo.ipi_zone, maxsockets); 13638032Speter} 13738032Speter 13838032Speterstatic struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 13938032Speter 14038032Speterstatic int 14138032Speterraw_append(struct inpcb *last, struct ip *ip, struct mbuf *n) 14238032Speter{ 14390792Sgshapiro int policyfail = 0; 14464562Sgshapiro 14564562Sgshapiro INP_LOCK_ASSERT(last); 14638032Speter 14764562Sgshapiro#if defined(IPSEC) || defined(FAST_IPSEC) 14864562Sgshapiro /* check AH/ESP integrity. */ 14964562Sgshapiro if (ipsec4_in_reject(n, last)) { 15064562Sgshapiro policyfail = 1; 15138032Speter#ifdef IPSEC 15290792Sgshapiro ipsecstat.in_polvio++; 15390792Sgshapiro#endif /*IPSEC*/ 15490792Sgshapiro /* do not inject data to pcb */ 15590792Sgshapiro } 15690792Sgshapiro#endif /*IPSEC || FAST_IPSEC*/ 15790792Sgshapiro#ifdef MAC 15890792Sgshapiro if (!policyfail && mac_check_inpcb_deliver(last, n) != 0) 15964562Sgshapiro policyfail = 1; 16090792Sgshapiro#endif 161285303Sgshapiro if (!policyfail) { 162285303Sgshapiro struct mbuf *opts = NULL; 163285303Sgshapiro 164285303Sgshapiro if ((last->inp_flags & INP_CONTROLOPTS) || 165285303Sgshapiro (last->inp_socket->so_options & SO_TIMESTAMP)) 166285303Sgshapiro ip_savecontrol(last, &opts, ip, n); 167285303Sgshapiro if (sbappendaddr(&last->inp_socket->so_rcv, 168285303Sgshapiro (struct sockaddr *)&ripsrc, n, opts) == 0) { 169285303Sgshapiro /* should notify about lost packet */ 170285303Sgshapiro m_freem(n); 171285303Sgshapiro if (opts) 172285303Sgshapiro m_freem(opts); 173285303Sgshapiro } else 174285303Sgshapiro sorwakeup(last->inp_socket); 175285303Sgshapiro } else 176285303Sgshapiro m_freem(n); 177285303Sgshapiro return policyfail; 178285303Sgshapiro} 179285303Sgshapiro 180285303Sgshapiro/* 18138032Speter * Setup generic address and protocol structures 18238032Speter * for raw_input routine, then pass them along with 18338032Speter * mbuf chain. 18438032Speter */ 18538032Spetervoid 18638032Speterrip_input(struct mbuf *m, int off) 18738032Speter{ 18838032Speter struct ip *ip = mtod(m, struct ip *); 18938032Speter int proto = ip->ip_p; 19038032Speter struct inpcb *inp, *last; 19138032Speter 19238032Speter INP_INFO_RLOCK(&ripcbinfo); 19338032Speter ripsrc.sin_addr = ip->ip_src; 19438032Speter last = NULL; 19538032Speter LIST_FOREACH(inp, &ripcb, inp_list) { 19638032Speter INP_LOCK(inp); 19738032Speter if (inp->inp_ip_p && inp->inp_ip_p != proto) { 19838032Speter docontinue: 19938032Speter INP_UNLOCK(inp); 20038032Speter continue; 20138032Speter } 20238032Speter#ifdef INET6 20364562Sgshapiro if ((inp->inp_vflag & INP_IPV4) == 0) 20438032Speter goto docontinue; 20564562Sgshapiro#endif 20638032Speter if (inp->inp_laddr.s_addr && 20738032Speter inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 20838032Speter goto docontinue; 20938032Speter if (inp->inp_faddr.s_addr && 21038032Speter inp->inp_faddr.s_addr != ip->ip_src.s_addr) 21138032Speter goto docontinue; 21238032Speter if (jailed(inp->inp_socket->so_cred)) 213110560Sgshapiro if (htonl(prison_getip(inp->inp_socket->so_cred)) != 214110560Sgshapiro ip->ip_dst.s_addr) 215110560Sgshapiro goto docontinue; 216110560Sgshapiro if (last) { 217110560Sgshapiro struct mbuf *n; 218110560Sgshapiro 21990792Sgshapiro n = m_copy(m, 0, (int)M_COPYALL); 220110560Sgshapiro if (n != NULL) 22190792Sgshapiro (void) raw_append(last, ip, n); 22290792Sgshapiro /* XXX count dropped packet */ 22390792Sgshapiro INP_UNLOCK(last); 22490792Sgshapiro } 22590792Sgshapiro last = inp; 22690792Sgshapiro } 22790792Sgshapiro if (last != NULL) { 22890792Sgshapiro if (raw_append(last, ip, m) != 0) 22990792Sgshapiro ipstat.ips_delivered--; 23090792Sgshapiro INP_UNLOCK(last); 23190792Sgshapiro } else { 23290792Sgshapiro m_freem(m); 23390792Sgshapiro ipstat.ips_noproto++; 23438032Speter ipstat.ips_delivered--; 23538032Speter } 23638032Speter INP_INFO_RUNLOCK(&ripcbinfo); 23738032Speter} 23838032Speter 23938032Speter/* 24064562Sgshapiro * Generate IP header and pass packet to ip_output. 24164562Sgshapiro * Tack on options user may have setup with control call. 24264562Sgshapiro */ 24364562Sgshapiroint 24464562Sgshapirorip_output(struct mbuf *m, struct socket *so, u_long dst) 24538032Speter{ 24664562Sgshapiro struct ip *ip; 24764562Sgshapiro int error; 24864562Sgshapiro struct inpcb *inp = sotoinpcb(so); 24964562Sgshapiro int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 25064562Sgshapiro 25164562Sgshapiro /* 25264562Sgshapiro * If the user handed us a complete IP packet, use it. 25364562Sgshapiro * Otherwise, allocate an mbuf for a header and fill it in. 25464562Sgshapiro */ 25564562Sgshapiro if ((inp->inp_flags & INP_HDRINCL) == 0) { 25664562Sgshapiro if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 25764562Sgshapiro m_freem(m); 25864562Sgshapiro return(EMSGSIZE); 25964562Sgshapiro } 26064562Sgshapiro M_PREPEND(m, sizeof(struct ip), M_TRYWAIT); 26164562Sgshapiro if (m == NULL) 26264562Sgshapiro return(ENOBUFS); 26364562Sgshapiro 26464562Sgshapiro INP_LOCK(inp); 26564562Sgshapiro ip = mtod(m, struct ip *); 26664562Sgshapiro ip->ip_tos = inp->inp_ip_tos; 26764562Sgshapiro ip->ip_off = 0; 26864562Sgshapiro ip->ip_p = inp->inp_ip_p; 26964562Sgshapiro ip->ip_len = m->m_pkthdr.len; 27064562Sgshapiro if (jailed(inp->inp_socket->so_cred)) 27164562Sgshapiro ip->ip_src.s_addr = 27264562Sgshapiro htonl(prison_getip(inp->inp_socket->so_cred)); 27364562Sgshapiro else 27464562Sgshapiro ip->ip_src = inp->inp_laddr; 27564562Sgshapiro ip->ip_dst.s_addr = dst; 27664562Sgshapiro ip->ip_ttl = inp->inp_ip_ttl; 27764562Sgshapiro } else { 27864562Sgshapiro if (m->m_pkthdr.len > IP_MAXPACKET) { 27964562Sgshapiro m_freem(m); 28064562Sgshapiro return(EMSGSIZE); 28164562Sgshapiro } 28264562Sgshapiro INP_LOCK(inp); 28364562Sgshapiro ip = mtod(m, struct ip *); 28464562Sgshapiro if (jailed(inp->inp_socket->so_cred)) { 28564562Sgshapiro if (ip->ip_src.s_addr != 28664562Sgshapiro htonl(prison_getip(inp->inp_socket->so_cred))) { 28764562Sgshapiro INP_UNLOCK(inp); 28864562Sgshapiro m_freem(m); 28964562Sgshapiro return (EPERM); 29064562Sgshapiro } 29164562Sgshapiro } 29264562Sgshapiro /* don't allow both user specified and setsockopt options, 29364562Sgshapiro and don't allow packet length sizes that will crash */ 29464562Sgshapiro if (((ip->ip_hl != (sizeof (*ip) >> 2)) 29564562Sgshapiro && inp->inp_options) 29680785Sgshapiro || (ip->ip_len > m->m_pkthdr.len) 29780785Sgshapiro || (ip->ip_len < (ip->ip_hl << 2))) { 29880785Sgshapiro INP_UNLOCK(inp); 29980785Sgshapiro m_freem(m); 30080785Sgshapiro return EINVAL; 30138032Speter } 30238032Speter if (ip->ip_id == 0) 30338032Speter#ifdef RANDOM_IP_ID 30438032Speter ip->ip_id = ip_randomid(); 30538032Speter#else 30638032Speter ip->ip_id = htons(ip_id++); 30738032Speter#endif 30838032Speter /* XXX prevent ip_output from overwriting header fields */ 30938032Speter flags |= IP_RAWOUTPUT; 31038032Speter ipstat.ips_rawout++; 31138032Speter } 31238032Speter 31338032Speter if (inp->inp_flags & INP_ONESBCAST) 31438032Speter flags |= IP_SENDONES; 31538032Speter 31638032Speter#ifdef MAC 31738032Speter mac_create_mbuf_from_inpcb(inp, m); 31838032Speter#endif 31938032Speter 32038032Speter error = ip_output(m, inp->inp_options, NULL, flags, 32164562Sgshapiro inp->inp_moptions, inp); 32238032Speter INP_UNLOCK(inp); 32338032Speter return error; 32438032Speter} 32538032Speter 32638032Speter/* 32738032Speter * Raw IP socket option processing. 32864562Sgshapiro * 32938032Speter * Note that access to all of the IP administrative functions here is 33038032Speter * implicitly protected by suser() as gaining access to a raw socket 33138032Speter * requires either that the thread pass a suser() check, or that it be 33264562Sgshapiro * passed a raw socket by another thread that has passed a suser() check. 33364562Sgshapiro * If FreeBSD moves to a more fine-grained access control mechanism, 33473188Sgshapiro * additional checks will need to be placed here if the raw IP attachment 33564562Sgshapiro * check is not equivilent the the check required for these 33673188Sgshapiro * administrative operations; in some cases, these checks are already 33764562Sgshapiro * present. 33873188Sgshapiro */ 33973188Sgshapiroint 34090792Sgshapirorip_ctloutput(struct socket *so, struct sockopt *sopt) 34190792Sgshapiro{ 34290792Sgshapiro struct inpcb *inp = sotoinpcb(so); 34390792Sgshapiro int error, optval; 34464562Sgshapiro 34538032Speter if (sopt->sopt_level != IPPROTO_IP) 34638032Speter return (EINVAL); 34764562Sgshapiro 34864562Sgshapiro error = 0; 34938032Speter 35038032Speter switch (sopt->sopt_dir) { 35138032Speter case SOPT_GET: 35238032Speter switch (sopt->sopt_name) { 35364562Sgshapiro case IP_HDRINCL: 35464562Sgshapiro optval = inp->inp_flags & INP_HDRINCL; 35564562Sgshapiro error = sooptcopyout(sopt, &optval, sizeof optval); 35638032Speter break; 35738032Speter 35838032Speter case IP_FW_ADD: /* ADD actually returns the body... */ 35938032Speter case IP_FW_GET: 36064562Sgshapiro case IP_FW_TABLE_GETSIZE: 36164562Sgshapiro case IP_FW_TABLE_LIST: 36264562Sgshapiro if (IPFW_LOADED) 36364562Sgshapiro error = ip_fw_ctl_ptr(sopt); 36464562Sgshapiro else 36538032Speter error = ENOPROTOOPT; 36638032Speter break; 36738032Speter 36838032Speter case IP_DUMMYNET_GET: 36938032Speter if (DUMMYNET_LOADED) 37038032Speter error = ip_dn_ctl_ptr(sopt); 37138032Speter else 37290792Sgshapiro error = ENOPROTOOPT; 37338032Speter break ; 37438032Speter 37564562Sgshapiro case MRT_INIT: 37638032Speter case MRT_DONE: 37790792Sgshapiro case MRT_ADD_VIF: 37890792Sgshapiro case MRT_DEL_VIF: 37990792Sgshapiro case MRT_ADD_MFC: 38090792Sgshapiro case MRT_DEL_MFC: 381102528Sgshapiro case MRT_VERSION: 38238032Speter case MRT_ASSERT: 38390792Sgshapiro case MRT_API_SUPPORT: 38438032Speter case MRT_API_CONFIG: 38564562Sgshapiro case MRT_ADD_BW_UPCALL: 38664562Sgshapiro case MRT_DEL_BW_UPCALL: 38764562Sgshapiro error = ip_mrouter_get ? ip_mrouter_get(so, sopt) : 38864562Sgshapiro EOPNOTSUPP; 38964562Sgshapiro break; 39064562Sgshapiro 39164562Sgshapiro default: 39238032Speter error = ip_ctloutput(so, sopt); 39364562Sgshapiro break; 39438032Speter } 39564562Sgshapiro break; 39664562Sgshapiro 39764562Sgshapiro case SOPT_SET: 39894334Sgshapiro switch (sopt->sopt_name) { 39994334Sgshapiro case IP_HDRINCL: 40094334Sgshapiro error = sooptcopyin(sopt, &optval, sizeof optval, 40166494Sgshapiro sizeof optval); 40238032Speter if (error) 40338032Speter break; 40466494Sgshapiro if (optval) 40566494Sgshapiro inp->inp_flags |= INP_HDRINCL; 40666494Sgshapiro else 40766494Sgshapiro inp->inp_flags &= ~INP_HDRINCL; 40890792Sgshapiro break; 40990792Sgshapiro 41090792Sgshapiro case IP_FW_ADD: 41190792Sgshapiro case IP_FW_DEL: 41290792Sgshapiro case IP_FW_FLUSH: 41364562Sgshapiro case IP_FW_ZERO: 41464562Sgshapiro case IP_FW_RESETLOG: 41564562Sgshapiro case IP_FW_TABLE_ADD: 41638032Speter case IP_FW_TABLE_DEL: 41738032Speter case IP_FW_TABLE_FLUSH: 41838032Speter if (IPFW_LOADED) 41938032Speter error = ip_fw_ctl_ptr(sopt); 420285303Sgshapiro else 421285303Sgshapiro error = ENOPROTOOPT; 422285303Sgshapiro break; 423285303Sgshapiro 424168515Sgshapiro case IP_DUMMYNET_CONFIGURE: 425168515Sgshapiro case IP_DUMMYNET_DEL: 426168515Sgshapiro case IP_DUMMYNET_FLUSH: 42738032Speter if (DUMMYNET_LOADED) 42838032Speter error = ip_dn_ctl_ptr(sopt); 42938032Speter else 43038032Speter error = ENOPROTOOPT ; 43138032Speter break ; 43238032Speter 43338032Speter case IP_RSVP_ON: 43438032Speter error = ip_rsvp_init(so); 43538032Speter break; 43638032Speter 43738032Speter case IP_RSVP_OFF: 43838032Speter error = ip_rsvp_done(); 43990792Sgshapiro break; 44038032Speter 44138032Speter case IP_RSVP_VIF_ON: 44238032Speter case IP_RSVP_VIF_OFF: 44338032Speter error = ip_rsvp_vif ? 44438032Speter ip_rsvp_vif(so, sopt) : EINVAL; 44538032Speter break; 44638032Speter 44764562Sgshapiro case MRT_INIT: 44838032Speter case MRT_DONE: 44938032Speter case MRT_ADD_VIF: 45090792Sgshapiro case MRT_DEL_VIF: 45138032Speter case MRT_ADD_MFC: 45243730Speter case MRT_DEL_MFC: 45343730Speter case MRT_VERSION: 45438032Speter case MRT_ASSERT: 45564562Sgshapiro case MRT_API_SUPPORT: 45643730Speter case MRT_API_CONFIG: 45738032Speter case MRT_ADD_BW_UPCALL: 45838032Speter case MRT_DEL_BW_UPCALL: 45938032Speter error = ip_mrouter_set ? ip_mrouter_set(so, sopt) : 46043730Speter EOPNOTSUPP; 46138032Speter break; 46238032Speter 46338032Speter default: 46490792Sgshapiro error = ip_ctloutput(so, sopt); 46538032Speter break; 46638032Speter } 46738032Speter break; 46838032Speter } 46990792Sgshapiro 47038032Speter return (error); 47138032Speter} 47264562Sgshapiro 47364562Sgshapiro/* 47438032Speter * This function exists solely to receive the PRC_IFDOWN messages which 47590792Sgshapiro * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa, 47664562Sgshapiro * and calls in_ifadown() to remove all routes corresponding to that address. 47738032Speter * It also receives the PRC_IFUP messages from if_up() and reinstalls the 47838032Speter * interface routes. 47938032Speter */ 48038032Spetervoid 48138032Speterrip_ctlinput(int cmd, struct sockaddr *sa, void *vip) 48238032Speter{ 48338032Speter struct in_ifaddr *ia; 48438032Speter struct ifnet *ifp; 48538032Speter int err; 48690792Sgshapiro int flags; 48764562Sgshapiro 48864562Sgshapiro switch (cmd) { 48938032Speter case PRC_IFDOWN: 49038032Speter TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 49198121Sgshapiro if (ia->ia_ifa.ifa_addr == sa 49298121Sgshapiro && (ia->ia_flags & IFA_ROUTE)) { 49398121Sgshapiro /* 49498121Sgshapiro * in_ifscrub kills the interface route. 49598121Sgshapiro */ 49698121Sgshapiro in_ifscrub(ia->ia_ifp, ia); 49798121Sgshapiro /* 49898121Sgshapiro * in_ifadown gets rid of all the rest of 49998121Sgshapiro * the routes. This is not quite the right 50098121Sgshapiro * thing to do, but at least if we are running 50198121Sgshapiro * a routing process they will come back. 50298121Sgshapiro */ 50398121Sgshapiro in_ifadown(&ia->ia_ifa, 0); 504110560Sgshapiro break; 505110560Sgshapiro } 506110560Sgshapiro } 507110560Sgshapiro break; 50838032Speter 50943730Speter case PRC_IFUP: 51043730Speter TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 51164562Sgshapiro if (ia->ia_ifa.ifa_addr == sa) 51264562Sgshapiro break; 51364562Sgshapiro } 51464562Sgshapiro if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) 51564562Sgshapiro return; 51664562Sgshapiro flags = RTF_UP; 51764562Sgshapiro ifp = ia->ia_ifa.ifa_ifp; 51890792Sgshapiro 51990792Sgshapiro if ((ifp->if_flags & IFF_LOOPBACK) 52038032Speter || (ifp->if_flags & IFF_POINTOPOINT)) 52164562Sgshapiro flags |= RTF_HOST; 522157001Sgshapiro 523157001Sgshapiro err = rtinit(&ia->ia_ifa, RTM_ADD, flags); 524157001Sgshapiro if (err == 0) 525157001Sgshapiro ia->ia_flags |= IFA_ROUTE; 526157001Sgshapiro break; 527157001Sgshapiro } 52838032Speter} 52964562Sgshapiro 53038032Speteru_long rip_sendspace = RIPSNDQ; 53190792Sgshapirou_long rip_recvspace = RIPRCVQ; 53290792Sgshapiro 53390792SgshapiroSYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW, 53464562Sgshapiro &rip_sendspace, 0, "Maximum outgoing raw IP datagram size"); 53564562SgshapiroSYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW, 53664562Sgshapiro &rip_recvspace, 0, "Maximum space for incoming raw IP datagrams"); 53764562Sgshapiro 53864562Sgshapirostatic int 53938032Speterrip_attach(struct socket *so, int proto, struct thread *td) 54038032Speter{ 54138032Speter struct inpcb *inp; 54238032Speter int error; 54338032Speter 54464562Sgshapiro /* XXX why not lower? */ 54538032Speter INP_INFO_WLOCK(&ripcbinfo); 54638032Speter inp = sotoinpcb(so); 54738032Speter if (inp) { 54838032Speter /* XXX counter, printf */ 54938032Speter INP_INFO_WUNLOCK(&ripcbinfo); 55038032Speter return EINVAL; 55138032Speter } 55238032Speter if (td && jailed(td->td_ucred) && !jail_allow_raw_sockets) { 55338032Speter INP_INFO_WUNLOCK(&ripcbinfo); 55438032Speter return (EPERM); 55538032Speter } 55638032Speter if (td && (error = suser_cred(td->td_ucred, PRISON_ROOT)) != 0) { 55738032Speter INP_INFO_WUNLOCK(&ripcbinfo); 55871345Sgshapiro return error; 55982017Sgshapiro } 56071345Sgshapiro if (proto >= IPPROTO_MAX || proto < 0) { 56171345Sgshapiro INP_INFO_WUNLOCK(&ripcbinfo); 56290792Sgshapiro return EPROTONOSUPPORT; 56371345Sgshapiro } 56471345Sgshapiro 56571345Sgshapiro error = soreserve(so, rip_sendspace, rip_recvspace); 56671345Sgshapiro if (error) { 56771345Sgshapiro INP_INFO_WUNLOCK(&ripcbinfo); 56838032Speter return error; 56964562Sgshapiro } 57064562Sgshapiro error = in_pcballoc(so, &ripcbinfo, "rawinp"); 57164562Sgshapiro if (error) { 57238032Speter INP_INFO_WUNLOCK(&ripcbinfo); 57338032Speter return error; 57438032Speter } 57538032Speter inp = (struct inpcb *)so->so_pcb; 57638032Speter INP_LOCK(inp); 57738032Speter INP_INFO_WUNLOCK(&ripcbinfo); 57838032Speter inp->inp_vflag |= INP_IPV4; 57938032Speter inp->inp_ip_p = proto; 58038032Speter inp->inp_ip_ttl = ip_defttl; 58138032Speter INP_UNLOCK(inp); 58238032Speter return 0; 58338032Speter} 58438032Speter 58538032Speterstatic void 58638032Speterrip_pcbdetach(struct socket *so, struct inpcb *inp) 58738032Speter{ 58838032Speter INP_INFO_WLOCK_ASSERT(&ripcbinfo); 58938032Speter INP_LOCK_ASSERT(inp); 59038032Speter 59138032Speter if (so == ip_mrouter && ip_mrouter_done) 59290792Sgshapiro ip_mrouter_done(); 59338032Speter if (ip_rsvp_force_done) 59438032Speter ip_rsvp_force_done(so); 59538032Speter if (so == ip_rsvpd) 59638032Speter ip_rsvp_done(); 59738032Speter in_pcbdetach(inp); 59838032Speter} 59990792Sgshapiro 60038032Speterstatic int 60138032Speterrip_detach(struct socket *so) 60238032Speter{ 60338032Speter struct inpcb *inp; 60438032Speter 60538032Speter INP_INFO_WLOCK(&ripcbinfo); 60638032Speter inp = sotoinpcb(so); 60738032Speter if (inp == 0) { 60838032Speter /* XXX counter, printf */ 60938032Speter INP_INFO_WUNLOCK(&ripcbinfo); 61064562Sgshapiro return EINVAL; 61138032Speter } 61238032Speter INP_LOCK(inp); 61338032Speter rip_pcbdetach(so, inp); 61438032Speter INP_INFO_WUNLOCK(&ripcbinfo); 61564562Sgshapiro return 0; 61664562Sgshapiro} 61764562Sgshapiro 61838032Speterstatic int 61966494Sgshapirorip_abort(struct socket *so) 62038032Speter{ 62138032Speter struct inpcb *inp; 62238032Speter 62338032Speter INP_INFO_WLOCK(&ripcbinfo); 62490792Sgshapiro inp = sotoinpcb(so); 62590792Sgshapiro if (inp == 0) { 62690792Sgshapiro INP_INFO_WUNLOCK(&ripcbinfo); 62738032Speter return EINVAL; /* ??? possible? panic instead? */ 62864562Sgshapiro } 62964562Sgshapiro INP_LOCK(inp); 63064562Sgshapiro soisdisconnected(so); 63138032Speter if (so->so_state & SS_NOFDREF) 63238032Speter rip_pcbdetach(so, inp); 63338032Speter else 63438032Speter INP_UNLOCK(inp); 63538032Speter INP_INFO_WUNLOCK(&ripcbinfo); 63638032Speter return 0; 63738032Speter} 63838032Speter 63938032Speterstatic int 64038032Speterrip_disconnect(struct socket *so) 64138032Speter{ 64238032Speter if ((so->so_state & SS_ISCONNECTED) == 0) 64338032Speter return ENOTCONN; 64471345Sgshapiro return rip_abort(so); 64538032Speter} 64638032Speter 64738032Speterstatic int 64838032Speterrip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 64938032Speter{ 65038032Speter struct sockaddr_in *addr = (struct sockaddr_in *)nam; 65138032Speter struct inpcb *inp; 65238032Speter 65338032Speter if (nam->sa_len != sizeof(*addr)) 65438032Speter return EINVAL; 65538032Speter 65638032Speter if (jailed(td->td_ucred)) { 65738032Speter if (addr->sin_addr.s_addr == INADDR_ANY) 65838032Speter addr->sin_addr.s_addr = 65938032Speter htonl(prison_getip(td->td_ucred)); 66038032Speter if (htonl(prison_getip(td->td_ucred)) != addr->sin_addr.s_addr) 66138032Speter return (EADDRNOTAVAIL); 662111823Sgshapiro } 663111823Sgshapiro 66443730Speter if (TAILQ_EMPTY(&ifnet) || 66538032Speter (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || 66638032Speter (addr->sin_addr.s_addr && 66790792Sgshapiro ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 66890792Sgshapiro return EADDRNOTAVAIL; 66990792Sgshapiro 67038032Speter INP_INFO_WLOCK(&ripcbinfo); 67138032Speter inp = sotoinpcb(so); 67238032Speter if (inp == 0) { 67338032Speter INP_INFO_WUNLOCK(&ripcbinfo); 67438032Speter return EINVAL; 67538032Speter } 67638032Speter INP_LOCK(inp); 67738032Speter inp->inp_laddr = addr->sin_addr; 67838032Speter INP_UNLOCK(inp); 67938032Speter INP_INFO_WUNLOCK(&ripcbinfo); 68038032Speter return 0; 68138032Speter} 68238032Speter 68390792Sgshapirostatic int 68490792Sgshapirorip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 68590792Sgshapiro{ 68690792Sgshapiro struct sockaddr_in *addr = (struct sockaddr_in *)nam; 68790792Sgshapiro struct inpcb *inp; 68890792Sgshapiro 68938032Speter if (nam->sa_len != sizeof(*addr)) 69098121Sgshapiro return EINVAL; 69198121Sgshapiro if (TAILQ_EMPTY(&ifnet)) 69298121Sgshapiro return EADDRNOTAVAIL; 69398121Sgshapiro if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) 69498121Sgshapiro return EAFNOSUPPORT; 69598121Sgshapiro 69698121Sgshapiro INP_INFO_WLOCK(&ripcbinfo); 69798121Sgshapiro inp = sotoinpcb(so); 69864562Sgshapiro if (inp == 0) { 69964562Sgshapiro INP_INFO_WUNLOCK(&ripcbinfo); 70038032Speter return EINVAL; 70138032Speter } 70238032Speter INP_LOCK(inp); 70343730Speter inp->inp_faddr = addr->sin_addr; 70443730Speter soisconnected(so); 70543730Speter INP_UNLOCK(inp); 70643730Speter INP_INFO_WUNLOCK(&ripcbinfo); 70738032Speter return 0; 70838032Speter} 70938032Speter 71038032Speterstatic int 71138032Speterrip_shutdown(struct socket *so) 71238032Speter{ 71338032Speter struct inpcb *inp; 71438032Speter 71538032Speter INP_INFO_RLOCK(&ripcbinfo); 71643730Speter inp = sotoinpcb(so); 71738032Speter if (inp == 0) { 71864562Sgshapiro INP_INFO_RUNLOCK(&ripcbinfo); 71990792Sgshapiro return EINVAL; 72064562Sgshapiro } 72138032Speter INP_LOCK(inp); 72243730Speter INP_INFO_RUNLOCK(&ripcbinfo); 72338032Speter socantsendmore(so); 72438032Speter INP_UNLOCK(inp); 72564562Sgshapiro return 0; 72638032Speter} 72738032Speter 72838032Speterstatic int 72938032Speterrip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 73038032Speter struct mbuf *control, struct thread *td) 73164562Sgshapiro{ 73264562Sgshapiro struct inpcb *inp; 73338032Speter u_long dst; 73490792Sgshapiro int ret; 73590792Sgshapiro 73690792Sgshapiro INP_INFO_WLOCK(&ripcbinfo); 73790792Sgshapiro inp = sotoinpcb(so); 73890792Sgshapiro if (so->so_state & SS_ISCONNECTED) { 73938032Speter if (nam) { 74038032Speter INP_INFO_WUNLOCK(&ripcbinfo); 74164562Sgshapiro m_freem(m); 74264562Sgshapiro return EISCONN; 74364562Sgshapiro } 74464562Sgshapiro dst = inp->inp_faddr.s_addr; 74564562Sgshapiro } else { 74664562Sgshapiro if (nam == NULL) { 74764562Sgshapiro INP_INFO_WUNLOCK(&ripcbinfo); 74838032Speter m_freem(m); 74964562Sgshapiro return ENOTCONN; 75064562Sgshapiro } 75164562Sgshapiro dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; 75264562Sgshapiro } 75364562Sgshapiro ret = rip_output(m, so, dst); 75438032Speter INP_INFO_WUNLOCK(&ripcbinfo); 75538032Speter return ret; 75664562Sgshapiro} 75738032Speter 75838032Speterstatic int 75938032Speterrip_pcblist(SYSCTL_HANDLER_ARGS) 76064562Sgshapiro{ 76164562Sgshapiro int error, i, n; 76264562Sgshapiro struct inpcb *inp, **inp_list; 76364562Sgshapiro inp_gen_t gencnt; 76464562Sgshapiro struct xinpgen xig; 76564562Sgshapiro 76690792Sgshapiro /* 76764562Sgshapiro * The process of preparing the TCB list is too time-consuming and 76864562Sgshapiro * resource-intensive to repeat twice on every request. 76938032Speter */ 770285303Sgshapiro if (req->oldptr == 0) { 771285303Sgshapiro n = ripcbinfo.ipi_count; 772285303Sgshapiro req->oldidx = 2 * (sizeof xig) 773285303Sgshapiro + (n + n/8) * sizeof(struct xinpcb); 774285303Sgshapiro return 0; 775285303Sgshapiro } 776285303Sgshapiro 777285303Sgshapiro if (req->newptr != 0) 778285303Sgshapiro return EPERM; 779285303Sgshapiro 78064562Sgshapiro /* 78171345Sgshapiro * OK, now we're committed to doing something. 78271345Sgshapiro */ 78371345Sgshapiro INP_INFO_RLOCK(&ripcbinfo); 78471345Sgshapiro gencnt = ripcbinfo.ipi_gencnt; 78564562Sgshapiro n = ripcbinfo.ipi_count; 78664562Sgshapiro INP_INFO_RUNLOCK(&ripcbinfo); 78764562Sgshapiro 78864562Sgshapiro xig.xig_len = sizeof xig; 78964562Sgshapiro xig.xig_count = n; 79064562Sgshapiro xig.xig_gen = gencnt; 79164562Sgshapiro xig.xig_sogen = so_gencnt; 79264562Sgshapiro error = SYSCTL_OUT(req, &xig, sizeof xig); 79364562Sgshapiro if (error) 79438032Speter return error; 79564562Sgshapiro 79664562Sgshapiro inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); 79764562Sgshapiro if (inp_list == 0) 79864562Sgshapiro return ENOMEM; 79964562Sgshapiro 80064562Sgshapiro INP_INFO_RLOCK(&ripcbinfo); 80164562Sgshapiro for (inp = LIST_FIRST(ripcbinfo.listhead), i = 0; inp && i < n; 80264562Sgshapiro inp = LIST_NEXT(inp, inp_list)) { 80364562Sgshapiro INP_LOCK(inp); 80464562Sgshapiro if (inp->inp_gencnt <= gencnt && 80564562Sgshapiro cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) { 80664562Sgshapiro /* XXX held references? */ 80764562Sgshapiro inp_list[i++] = inp; 80864562Sgshapiro } 80964562Sgshapiro INP_UNLOCK(inp); 81064562Sgshapiro } 81164562Sgshapiro INP_INFO_RUNLOCK(&ripcbinfo); 81264562Sgshapiro n = i; 81364562Sgshapiro 81464562Sgshapiro error = 0; 81564562Sgshapiro for (i = 0; i < n; i++) { 81671345Sgshapiro inp = inp_list[i]; 81771345Sgshapiro if (inp->inp_gencnt <= gencnt) { 81871345Sgshapiro struct xinpcb xi; 81938032Speter xi.xi_len = sizeof xi; 82073188Sgshapiro /* XXX should avoid extra copy */ 82171345Sgshapiro bcopy(inp, &xi.xi_inp, sizeof *inp); 82271345Sgshapiro if (inp->inp_socket) 82371345Sgshapiro sotoxsocket(inp->inp_socket, &xi.xi_socket); 82471345Sgshapiro error = SYSCTL_OUT(req, &xi, sizeof xi); 82571345Sgshapiro } 82671345Sgshapiro } 82771345Sgshapiro if (!error) { 82871345Sgshapiro /* 82971345Sgshapiro * Give the user an updated idea of our state. 83071345Sgshapiro * If the generation differs from what we told 83171345Sgshapiro * her before, she knows that something happened 83271345Sgshapiro * while we were processing this request, and it 83338032Speter * might be necessary to retry. 83464562Sgshapiro */ 83564562Sgshapiro INP_INFO_RLOCK(&ripcbinfo); 83664562Sgshapiro xig.xig_gen = ripcbinfo.ipi_gencnt; 83764562Sgshapiro xig.xig_sogen = so_gencnt; 83843730Speter xig.xig_count = ripcbinfo.ipi_count; 83964562Sgshapiro INP_INFO_RUNLOCK(&ripcbinfo); 84043730Speter error = SYSCTL_OUT(req, &xig, sizeof xig); 84138032Speter } 84238032Speter free(inp_list, M_TEMP); 84364562Sgshapiro return error; 84464562Sgshapiro} 84564562Sgshapiro 84638032Speter/* 84738032Speter * This is the wrapper function for in_setsockaddr. We just pass down 84838032Speter * the pcbinfo for in_setpeeraddr to lock. 84938032Speter */ 85038032Speterstatic int 85138032Speterrip_sockaddr(struct socket *so, struct sockaddr **nam) 85238032Speter{ 85338032Speter return (in_setsockaddr(so, nam, &ripcbinfo)); 85438032Speter} 85538032Speter 85638032Speter/* 85764562Sgshapiro * This is the wrapper function for in_setpeeraddr. We just pass down 85864562Sgshapiro * the pcbinfo for in_setpeeraddr to lock. 85964562Sgshapiro */ 86064562Sgshapirostatic int 86138032Speterrip_peeraddr(struct socket *so, struct sockaddr **nam) 86238032Speter{ 86338032Speter return (in_setpeeraddr(so, nam, &ripcbinfo)); 86438032Speter} 86538032Speter 86638032Speter 86738032SpeterSYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, 0, 0, 86838032Speter rip_pcblist, "S,xinpcb", "List of active raw IP sockets"); 86943730Speter 87064562Sgshapirostruct pr_usrreqs rip_usrreqs = { 87143730Speter rip_abort, pru_accept_notsupp, rip_attach, rip_bind, rip_connect, 87238032Speter pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, 87338032Speter pru_listen_notsupp, rip_peeraddr, pru_rcvd_notsupp, 87438032Speter pru_rcvoob_notsupp, rip_send, pru_sense_null, rip_shutdown, 87538032Speter rip_sockaddr, sosend, soreceive, sopoll, in_pcbsosetlabel 87638032Speter}; 87738032Speter