/* $KAME: natpt_usrreq.c,v 1.9 2000/03/25 07:23:57 sumikawa Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include /* FreeBSD330 compiler complain that do not #include ioctl.h in the kernel, */ /* Include xxxio.h instead */ /* #include */ #include #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include /* * */ #define NATPTSNDQ (8192) #define NATPTRCVQ (8192) u_long natpt_sendspace = NATPTSNDQ; u_long natpt_recvspace = NATPTRCVQ; #if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 static struct rawcb ptrcb; #else LIST_HEAD(, rawcb) ptrcb; #endif static struct sockaddr natpt_dst = {2, PF_INET}; #ifdef notused static struct sockaddr natpt_src = {2, PF_INET}; #endif #if 0 int natpt_sosetopt __P((struct socket *, int, struct mbuf *)); int natpt_sogetopt __P((struct socket *, int, struct mbuf *)); #endif static int _natptSetIf __P((caddr_t)); static int _natptGetIf __P((caddr_t)); static int _natptSetValue __P((caddr_t)); static int _natptTestLog __P((caddr_t)); void natpt_init __P((void)); #ifdef __bsdi__ int natpt_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); #elif defined(__NetBSD__) int natpt_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); #endif /* defined(__bsdi__) || defined(__NetBSD__) */ #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int natpt_uabort __P((struct socket *)); int natpt_uattach __P((struct socket *, int, struct proc *)); int natpt_ubind __P((struct socket *, struct sockaddr *, struct proc *)); int natpt_uconnect __P((struct socket *, struct sockaddr *, struct proc *)); int natpt_udetach __P((struct socket *)); int natpt_ucontrol __P((struct socket *, u_long, caddr_t, struct ifnet *, struct proc *)); #endif /* defined(__FreeBSD__) && __FreeBSD__ >= 3 */ int natpt_attach __P((struct socket *, int)); int natpt_control __P((struct socket *, int, caddr_t, struct ifnet *)); int natpt_detach __P((struct socket *)); int natpt_disconnect __P((struct socket *)); #ifdef __FreeBSD__ #if __FreeBSD__ >= 3 struct pr_usrreqs natpt_usrreqs = { natpt_uabort, NULL, natpt_uattach, natpt_ubind, natpt_uconnect, NULL, natpt_ucontrol, natpt_udetach, natpt_disconnect, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, sosend, soreceive, sopoll }; #else struct pr_usrreqs natpt_usrreqs = { NULL, NULL, natpt_attach, NULL, NULL, NULL, natpt_control, natpt_detach, natpt_disconnect, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #endif /* __FreeBSD__ >= 3 */ #endif /* __FreeBSD__ */ /* * */ void natpt_init() { natpt_initialized = 0; ip6_protocol_tr = 0; init_tslot(); #if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 ptrcb.rcb_next = ptrcb.rcb_prev = &ptrcb; #else LIST_INIT(&ptrcb); #endif printf("NATPT: initialized.\n"); } void natpt_input(struct mbuf *m0, struct sockproto *proto, struct sockaddr *src, struct sockaddr *dst) { struct rawcb *rp; struct mbuf *m = m0; struct socket *last; int sockets; last = 0; #if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 for (rp = ptrcb.rcb_next; rp != &ptrcb; rp = rp->rcb_next) #else for (rp = ptrcb.lh_first; rp != 0; rp = rp->rcb_list.le_next) #endif { if (rp->rcb_proto.sp_family != proto->sp_family) continue; if (rp->rcb_proto.sp_protocol && (rp->rcb_proto.sp_protocol != proto->sp_protocol)) continue; #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) continue; if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) continue; if (last) { struct mbuf *n; if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { if (sbappendaddr(&last->so_rcv, src, n, (struct mbuf *)NULL) == 0) m_freem(n); /* should notify about lost packet */ else { sorwakeup(last); sockets++; } } } last = rp->rcb_socket; } if (last) { if (sbappendaddr(&last->so_rcv, src, m, (struct mbuf *)NULL) == 0) m_freem(m); else { sorwakeup(last); sockets++; } } else m_freem(m); } #if defined(__bsdi__) || defined(__NetBSD__) int natpt_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control #ifdef __NetBSD__ ,struct proc *p #endif ) { struct rawcb *rp = sotorawcb(so); int error = 0; if ((rp == NULL) && (req != PRU_ATTACH)) { m_freem(m); return (EINVAL); } switch (req) { case PRU_ATTACH: error = natpt_attach(so, (int)nam); break; case PRU_DETACH: error = natpt_detach(so); break; case PRU_DISCONNECT: if (rp->rcb_faddr == NULL) { error = ENOTCONN; break; } rp->rcb_faddr = NULL; raw_disconnect(rp); soisdisconnected(so); break; case PRU_SEND: case PRU_BIND: case PRU_LISTEN: case PRU_CONNECT: case PRU_ACCEPT: case PRU_SHUTDOWN: case PRU_RCVD: case PRU_ABORT: error = EOPNOTSUPP; break; case PRU_CONTROL: error = natpt_control(so, (int)m, (caddr_t)nam, (struct ifnet *)NULL); return (error); break; case PRU_SENSE: case PRU_RCVOOB: case PRU_SENDOOB: case PRU_SOCKADDR: case PRU_PEERADDR: case PRU_CONNECT2: case PRU_FASTTIMO: case PRU_SLOWTIMO: case PRU_PROTORCV: case PRU_PROTOSEND: error = EOPNOTSUPP; break; default: panic("raw_usrreq"); } if (m != NULL) m_freem(m); return (error); } #endif /* defined(__bsdi__) || defined(__NetBSD__) */ #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) int natpt_uabort(struct socket *so) { struct rawcb *rp = sotorawcb(so); if (rp == 0) return (EINVAL); raw_disconnect(rp); sofree(so); soisdisconnected(so); return (0); } int natpt_uattach(struct socket *so, int proto, struct proc *p) { int error; #if ISFB31 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return (error); #else if ((so->so_state & SS_PRIV) != 0) return (EPERM); #endif return (natpt_attach(so, proto)); } int natpt_ubind(struct socket *so, struct sockaddr *nam, struct proc *p) { return (EINVAL); } int natpt_uconnect(struct socket *so, struct sockaddr *nam, struct proc *p) { return (EINVAL); } int natpt_ucontrol(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct proc *p) { return (natpt_control(so, cmd, data, ifp)); } int natpt_udetach(struct socket *so) { struct rawcb *rp = sotorawcb(so); if (rp == 0) return (EINVAL); return (natpt_detach(so)); } #endif /* defined(__FreeBSD__) && __FreeBSD__ >= 3 */ int natpt_attach(struct socket *so, int proto) { struct rawcb *rp; int error; if (so->so_pcb == NULL) { MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); so->so_pcb = (caddr_t)rp; bzero(rp, sizeof(*rp)); } if ((rp = sotorawcb(so)) == NULL) return (ENOBUFS); if ((error = soreserve(so, natpt_sendspace, natpt_recvspace))) return (error); rp->rcb_socket = so; rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family; rp->rcb_proto.sp_protocol = proto; #if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 insque(rp, &ptrcb); #else LIST_INSERT_HEAD(&ptrcb, rp, rcb_list); #endif /* The socket is always "connected" because we always know "where" to send the packet */ rp->rcb_faddr = &natpt_dst; soisconnected(so); return (0); } int natpt_detach(struct socket *so) { struct rawcb *rp = sotorawcb(so); if (rp == NULL) return (ENOTCONN); so->so_pcb = NULL; sofree(so); #if defined(__bsdi__) || defined(__FreeBSD__) && __FreeBSD__ <= 2 remque(rp); #else LIST_REMOVE(rp, rcb_list); #endif if (rp->rcb_laddr) m_freem(dtom(rp->rcb_laddr)); if (rp->rcb_faddr) m_freem(dtom(rp->rcb_faddr)); FREE(rp, M_PCB); return (0); } int natpt_disconnect(struct socket *so) { struct rawcb *rp = sotorawcb(so); if (rp == NULL) return (EINVAL); if (rp->rcb_faddr == NULL) return (ENOTCONN); rp->rcb_faddr = NULL; raw_disconnect(rp); soisdisconnected(so); return (0); } int natpt_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp) { if (natpt_initialized == 0) natpt_initialize(); switch (cmd) { case SIOCSETIF: return (_natptSetIf(data)); case SIOCGETIF: return (_natptGetIf(data)); case SIOCENBTRANS: return (_natptEnableTrans(data)); case SIOCDSBTRANS: return (_natptDisableTrans(data)); case SIOCSETRULE: return (_natptSetRule(data)); case SIOCFLUSHRULE: return (_natptFlushRule(data)); case SIOCSETPREFIX: return (_natptSetPrefix(data)); case SIOCSETVALUE: return (_natptSetValue(data)); case SIOCTESTLOG: return (_natptTestLog(data)); case SIOCBREAK: return (_natptBreak()); } return (EINVAL); } /* * */ static int _natptSetIf(caddr_t addr) { struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; struct ifBox *ifb; if (((ifb = natpt_asIfBox(mbx->m_ifName)) == NULL) && ((ifb = natpt_setIfBox(mbx->m_ifName)) == NULL)) return (ENXIO); if (ifb->side != noSide) { char WoW[LBFSZ]; sprintf(WoW, "[natpt]: interface `%s\' already configured.", mbx->m_ifName); natpt_logMsg(LOG_WARNING, WoW, strlen(WoW)); return (EALREADY); } { char WoW[LBFSZ]; char *s; natpt_ip6src = ifb->ifnet; if (mbx->flags == IF_EXTERNAL) ifb->side = outSide, s = "outside"; else ifb->side = inSide, s = "inside"; sprintf(WoW, "[natpt]: interface `%s\' set as %s.", mbx->m_ifName, s); natpt_logMsg(LOG_INFO, WoW, strlen(WoW)); } return (0); } static int _natptGetIf(caddr_t addr) { struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; struct ifBox *ifb; if (((ifb = natpt_asIfBox(mbx->m_ifName)) == NULL) && ((ifb = natpt_setIfBox(mbx->m_ifName)) == NULL)) return (ENXIO); { switch (ifb->side) { case outSide: mbx->flags |= IF_EXTERNAL; break; case inSide: mbx->flags |= IF_INTERNAL; break; default: mbx->flags = -1; break; } } return (0); } static int _natptSetValue(caddr_t addr) { struct natpt_msgBox *mbx = (struct natpt_msgBox *)addr; switch (mbx->flags) { case NATPT_DEBUG: natpt_debug = *((u_int *)mbx->m_aux); break; case NATPT_DUMP: natpt_dump = *((u_int *)mbx->m_aux); break; } return (0); } static int _natptTestLog(caddr_t addr) { char *fragile; struct natpt_msgBox *mbox = (struct natpt_msgBox *)addr; MALLOC(fragile, char *, mbox->size, M_TEMP, M_WAITOK); copyin(mbox->freight, fragile, mbox->size); natpt_logMsg(LOG_DEBUG, fragile, mbox->size); FREE(fragile, M_TEMP); return (0); }