39#error "IPDIVERT requires INET"
43#include <sys/eventhandler.h>
44#include <sys/kernel.h>
46#include <sys/malloc.h>
48#include <sys/module.h>
49#include <sys/kernel.h>
52#include <sys/protosw.h>
53#include <sys/socket.h>
54#include <sys/socketvar.h>
55#include <sys/sysctl.h>
59#include <net/if_var.h>
60#include <net/netisr.h>
70#include <netinet6/ip6_var.h>
72#if defined(SCTP) || defined(SCTP_SUPPORT)
76#include <security/mac/mac_framework.h>
84#define DIVSNDQ (65536 + 100)
85#define DIVRCVQ (65536 + 100)
115#define V_divcbinfo VNET(divcbinfo)
157 struct mbuf *m = *mp;
161 return (IPPROTO_DONE);
169 return (inp->inp_lport == nport);
198 if (m->m_len <
sizeof(
struct ip) &&
199 (m = m_pullup(m,
sizeof(
struct ip))) == NULL)
201 ip = mtod(m,
struct ip *);
204 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
206 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
208#if defined(SCTP) || defined(SCTP_SUPPORT)
209 if (m->m_pkthdr.csum_flags & CSUM_SCTP) {
211 m->m_pkthdr.csum_flags &= ~CSUM_SCTP;
215 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
216 in6_delayed_cksum(m, m->m_pkthdr.len -
218 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
220#if defined(SCTP) || defined(SCTP_SUPPORT)
221 if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) {
222 sctp_delayed_cksum(m,
sizeof(
struct ip6_hdr));
223 m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
227 bzero(&divsrc,
sizeof(divsrc));
228 divsrc.
sin_len =
sizeof(divsrc);
244 ifp = m->m_pkthdr.rcvif;
245 CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
246 if (ifa->ifa_addr->sa_family != AF_INET)
256 if (m->m_pkthdr.rcvif) {
275 strlcpy(divsrc.
sin_zero, m->m_pkthdr.rcvif->if_xname,
282 nport = htons((u_int16_t)(((
struct ipfw_rule_ref *)(mtag+1))->info));
283 while ((inp =
inp_next(&inpi)) != NULL) {
285 SOCKBUF_LOCK(&sa->so_rcv);
286 if (sbappendaddr_locked(&sa->so_rcv,
287 (
struct sockaddr *)&divsrc, m, NULL) == 0) {
288 soroverflow_locked(sa);
291 sorwakeup_locked(sa);
312 struct mbuf *control)
314 struct epoch_tracker et;
328 return (EAFNOSUPPORT);
330 if (sin->
sin_len !=
sizeof(*sin)) {
340 m->m_pkthdr.rcvif = NULL;
342 M_SETFIB(m, so->so_fibnum);
353 m_tag_prepend(m, mtag);
378 if ( i > 0 && i <
sizeof(sin->
sin_zero))
379 m->m_pkthdr.rcvif = ifunit(sin->
sin_zero);
382 ip = mtod(m,
struct ip *);
394 return (EAFNOSUPPORT);
419 struct ip *
const ip = mtod(m,
struct ip *);
420 struct mbuf *options;
433 if ((((
ip->
ip_hl << 2) !=
sizeof(
struct ip)) &&
435 ((u_short)ntohs(
ip->
ip_len) > m->m_pkthdr.len)) {
447 if (((u_short)ntohs(ip6->ip6_plen) > m->m_pkthdr.len)) {
461 mac_inpcb_create_mbuf(inp, m);
476 (
"multicast options set on a divert socket"));
487 if (options == NULL) {
504 error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
526 if (m->m_pkthdr.rcvif == NULL) {
536 ifa = ifa_ifwithaddr((
struct sockaddr *) sin);
539 return (EADDRNOTAVAIL);
541 m->m_pkthdr.rcvif = ifa->ifa_ifp;
544 mac_socket_create_mbuf(so, m);
549 ip = mtod(m,
struct ip *);
555 m->m_flags |= M_MCAST;
557 m->m_flags |= M_BCAST;
558 netisr_queue_src(NETISR_IP, (uintptr_t)so, m);
562 netisr_queue_src(NETISR_IPV6, (uintptr_t)so, m);
580 KASSERT(inp == NULL, (
"div_attach: inp != NULL"));
582 error = priv_check(td, PRIV_NETINET_DIVERT);
592 inp = (
struct inpcb *)so->so_pcb;
606 KASSERT(inp != NULL, (
"div_detach: inp == NULL"));
613div_bind(
struct socket *so,
struct sockaddr *nam,
struct thread *td)
619 KASSERT(inp != NULL, (
"div_bind: inp == NULL"));
627 if (nam->sa_family != AF_INET)
646 KASSERT(inp != NULL, (
"div_shutdown: inp == NULL"));
654div_send(
struct socket *so,
int flags,
struct mbuf *m,
struct sockaddr *nam,
655 struct mbuf *control,
struct thread *td)
659 if (m->m_len < sizeof (
struct ip) &&
660 (m = m_pullup(m,
sizeof (
struct ip))) == NULL) {
681 if (req->newptr != 0)
684 if (req->oldptr == 0) {
688 n += imax(n / 8, 10);
689 req->oldidx = 2 * (
sizeof xig) + n *
sizeof(
struct xinpcb);
693 if ((error = sysctl_wire_old_buffer(req, 0)) != 0)
696 bzero(&xig,
sizeof(xig));
697 xig.xig_len =
sizeof xig;
700 xig.xig_sogen = so_gencnt;
701 error = SYSCTL_OUT(req, &xig,
sizeof xig);
705 while ((inp =
inp_next(&inpi)) != NULL) {
710 error = SYSCTL_OUT(req, &xi,
sizeof xi);
727 xig.xig_sogen = so_gencnt;
729 error = SYSCTL_OUT(req, &xig,
sizeof xig);
736static SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, divert,
737 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
740 CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
742 "List of active divert sockets");
759 .pr_protocol = IPPROTO_DIVERT,
760 .pr_flags = PR_ATOMIC|PR_ADDR,
809 err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW);
static SYSCTL_NODE(_net_inet_accf, OID_AUTO, http, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "HTTP accept filter")
SYSCTL_PROC(_net_inet_tcp_cc, OID_AUTO, algorithm, CTLFLAG_VNET|CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, NULL, 0, cc_default_algo, "A", "Default congestion control algorithm")
int in_broadcast(struct in_addr in, struct ifnet *ifp)
int in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
struct inpcb * inp_next(struct inpcb_iterator *ii)
int in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo)
void in_pcbinfo_destroy(struct inpcbinfo *pcbinfo)
void in_pcbtoxinpcb(const struct inpcb *inp, struct xinpcb *xi)
void in_pcbsosetlabel(struct socket *so)
void in_pcbdetach(struct inpcb *inp)
void in_pcbinfo_init(struct inpcbinfo *pcbinfo, struct inpcbstorage *pcbstor, u_int hash_nelements, u_int porthash_nelements)
void in_pcbfree(struct inpcb *inp)
#define INP_HASH_WUNLOCK(ipi)
#define INP_ALL_ITERATOR(_ipi, _lock)
int in_getsockaddr(struct socket *so, struct sockaddr **nam)
int in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *)
#define INP_INFO_WUNLOCK(ipi)
int in_getpeeraddr(struct socket *so, struct sockaddr **nam)
#define INP_HASH_WLOCK(ipi)
#define INP_INFO_WLOCK(ipi)
#define INP_ITERATOR(_ipi, _lock, _match, _ctx)
static int div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct thread *td)
MODULE_VERSION(ipdivert, 1)
static int div_pcblist(SYSCTL_HANDLER_ARGS)
static int div_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
static int div_modevent(module_t mod, int type, void *unused)
static u_long div_sendspace
static void div_init(void *arg __unused)
MODULE_DEPEND(ipdivert, ipfw, 3, 3, 3)
VNET_DEFINE_STATIC(struct inpcbinfo, divcbinfo)
static int div_shutdown(struct socket *so)
static u_long div_recvspace
static void div_detach(struct socket *so)
static int div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, struct mbuf *control)
static void div_destroy(void *unused __unused)
static bool div_port_match(const struct inpcb *inp, void *v)
struct protosw div_protosw
VNET_SYSINIT(div_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, div_init, NULL)
static int div_output_inbound(int fmaily, struct socket *so, struct mbuf *m, struct sockaddr_in *sin)
INPCBSTORAGE_DEFINE(divcbstor, "divinp", "divcb", "div", "divhash")
static int div_input(struct mbuf **mp, int *offp, int proto)
static void divert_packet(struct mbuf *m, bool incoming)
VNET_SYSUNINIT(divert, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, div_destroy, NULL)
DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY)
static int div_attach(struct socket *so, int proto, struct thread *td)
static moduledata_t ipdivertmod
struct pr_usrreqs div_usrreqs
static int div_output_outbound(int family, struct socket *so, struct mbuf *m)
int ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, struct ip_moptions *imo, struct inpcb *inp)
void in_delayed_cksum(struct mbuf *m)
#define KMOD_IPSTAT_DEC(name)
#define IP_ALLOWBROADCAST
#define KMOD_IPSTAT_INC(name)
void(* ip_divert_ptr)(struct mbuf *m, bool incoming)
struct socket * inp_socket
struct mbuf * inp_options
struct ip_moptions * inp_moptions
struct in_addr ip_src ip_dst