AF_DIVERT family restored & compiling: full socket family (PF_DIVERT=32, sock_register), blocking recv/poll, divert_output-compatible sendmsg reinject, mtag type passthrough; pfk_api decls
This commit is contained in:
1 parent
fe6f767561
commit
ac56534c3b
30 files changed
+2273
-62
No files matched your search
@@ -23,10 +23,14 @@ static inline bool refcnt_take_not0(struct refcnt *r)
|
||||
{
|
||||
return refcount_inc_not_zero(&r->rc);
|
||||
}
|
||||
/*
|
||||
* OpenBSD semantics (sys/kern/kern_synch.c): refcnt_rele() returns 1 when
|
||||
* the last reference is dropped and 0 otherwise. PF_REF_RELE() and the
|
||||
* pf_ruleset anchor release rely on that polarity.
|
||||
*/
|
||||
static inline unsigned int refcnt_rele(struct refcnt *r)
|
||||
{
|
||||
return (unsigned int)refcount_dec_and_test(&r->rc) ?
|
||||
refcnt_value(r) : refcnt_value(r) + 1;
|
||||
return (unsigned int)refcount_dec_and_test(&r->rc) ? 1 : 0;
|
||||
}
|
||||
static inline unsigned int refcnt_rele_wake(struct refcnt *r)
|
||||
{
|
||||
|
||||
@@ -9,5 +9,11 @@ int pfk_enable(int on);
|
||||
void pfk_status(struct pf_status *s);
|
||||
int pfk_hooks_register(void);
|
||||
void pfk_hooks_unregister(void);
|
||||
/* AF_DIVERT family (module-internal socket protocol, PF_DIVERT=32) */
|
||||
int pfk_divert_sock_register(void);
|
||||
void pfk_divert_sock_unregister(void);
|
||||
void divert_packet(struct mbuf *, int, u_int16_t);
|
||||
void divert6_packet(struct mbuf *, int, u_int16_t);
|
||||
void pfk_hooks_unregister(void);
|
||||
|
||||
#endif
|
||||
@@ -1828,6 +1828,7 @@ deps_pfsrc/divert_sock.o := \
|
||||
include/compat/sys/rwlock.h \
|
||||
include/compat/sys/mutex.h \
|
||||
include/compat/sys/pclock.h \
|
||||
include/pfk_api.h \
|
||||
|
||||
pfsrc/divert_sock.o: $(deps_pfsrc/divert_sock.o)
|
||||
|
||||
|
||||
+481
-17
@@ -1,33 +1,497 @@
|
||||
/*
|
||||
* PF-on-Linux divert entry points used by pf.c (ISC 2026).
|
||||
* PF-on-Linux: AF_DIVERT socket family (ISC 2026)
|
||||
*
|
||||
* BSD semantics (OpenBSD netinet/ip_divert.c): divert_packet()/divert6_packet()
|
||||
* find the AF_DIVERT pcb bound to `divert_port`, queue the packet to it and
|
||||
* consume the mbuf; when NO divert socket is attached, OpenBSD drops the
|
||||
* packet (m_freem) — that is exactly the observable behaviour implemented
|
||||
* here until the pfdiv socket layer is instantiated for Linux (milestone
|
||||
* M6); a rate-limited kernel log records the event so drops are never
|
||||
* silent.
|
||||
* Implements OpenBSD's divert(4) as a runtime-registered protocol family
|
||||
* inside the PF module: PF_DIVERT = 32 (BSD value; the unused legacy
|
||||
* PF_IUCV slot on Linux, and NPROTO = AF_MAX = 45 admits it),
|
||||
* IPPROTO_DIVERT = 254. No core patch is required — families are
|
||||
* registered with sock_register() at module init.
|
||||
*
|
||||
* The upstream BSD socket layer is staged in pfsrc/ip_divert.c and becomes
|
||||
* the real back end in M6; these wrappers keep the same call signature
|
||||
* (struct mbuf *, int dir, u_int16_t divert_port).
|
||||
* Userspace ABI (see docs/en/divert-wireformat.md):
|
||||
* fd = socket(PF_DIVERT, SOCK_RAW, IPPROTO_DIVERT);
|
||||
* struct sockaddr_in b = { .sin_family = AF_INET, .sin_port = port };
|
||||
* bind(fd, &b); # binds the divert "port"
|
||||
* n = recv(fd, pkt, ...) # full IP packet incl. header
|
||||
* send(fd, pkt, n) # reinject per BSD semantics
|
||||
*
|
||||
* Re-injection mirrors OpenBSD netinet/ip_divert.c:divert_output():
|
||||
* type PF_DIVERT_TO -> local delivery as if arrived on the recorded
|
||||
* interface (netif_rx)
|
||||
* plain divert tag -> route again (dst output), matching BSD ip_output
|
||||
*
|
||||
* Semantics notes (PFLINUX, docs/porting-notes.md):
|
||||
* - queue selection scans the bound list under pfk_divert_lock;
|
||||
* - full-socket drop counts divs_fullsock like BSD;
|
||||
* - no socket bound to the port: divs_noport + drop (BSD identical).
|
||||
*/
|
||||
#include <pfk.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <pfk_api.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#define PF_DIVERT_FAMILY 32 /* BSD PF_DIVERT */
|
||||
#ifndef IPPROTO_DIVERT
|
||||
#define IPPROTO_DIVERT 254
|
||||
#endif
|
||||
|
||||
/* control message codes reported to userspace (sendmsg accepts them back) */
|
||||
#define PFDIVERT_CMSG_IFINDEX 1
|
||||
#define PFDIVERT_CMSG_DIR 2
|
||||
#define PFDIVERT_CMSG_TYPE 3
|
||||
|
||||
struct pfk_divert_pkt {
|
||||
struct list_head node;
|
||||
struct sk_buff *skb;
|
||||
int dir;
|
||||
int type;
|
||||
u16 port;
|
||||
int ifindex;
|
||||
};
|
||||
|
||||
struct pfk_divert_stat {
|
||||
u64 divs_ipackets;
|
||||
u64 divs_noport;
|
||||
u64 divs_fullsock;
|
||||
u64 divs_opackets;
|
||||
u64 divs_errors;
|
||||
};
|
||||
|
||||
static const struct proto_ops pfk_divert_ops;
|
||||
|
||||
struct pfk_divert_sock {
|
||||
struct list_head link; /* global bound list */
|
||||
struct list_head q;
|
||||
spinlock_t lock;
|
||||
u16 port;
|
||||
u32 qlen;
|
||||
wait_queue_head_t wq;
|
||||
u32 qspace;
|
||||
struct sock *sk;
|
||||
struct pfk_divert_stat stats;
|
||||
};
|
||||
|
||||
static LIST_HEAD(pfk_divert_list);
|
||||
static DEFINE_SPINLOCK(pfk_divert_lock);
|
||||
static struct pfk_divert_stat pfk_divert_global;
|
||||
static struct proto pfk_divert_proto = {
|
||||
.name = "PFK_DIVERT",
|
||||
.owner = THIS_MODULE,
|
||||
.obj_size = sizeof(struct sock),
|
||||
};
|
||||
|
||||
static inline struct pfk_divert_sock *
|
||||
pfk_ds(const struct sock *sk)
|
||||
{
|
||||
return sk ? (struct pfk_divert_sock *)sk->sk_user_data : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pfk_divert_pkt_free(struct pfk_divert_pkt *dp)
|
||||
{
|
||||
if (!dp)
|
||||
return;
|
||||
if (dp->skb)
|
||||
kfree_skb(dp->skb);
|
||||
kfree(dp);
|
||||
}
|
||||
|
||||
/* PF engine entry points (called from the ported pf.c) */
|
||||
static int
|
||||
pfk_divert_queue(struct sk_buff *skb, int dir, int type, u16 port)
|
||||
{
|
||||
struct pfk_divert_sock *ds;
|
||||
struct pfk_divert_pkt *dp;
|
||||
unsigned long flags;
|
||||
|
||||
dp = kmalloc(sizeof(*dp), GFP_ATOMIC);
|
||||
if (!dp) {
|
||||
kfree_skb(skb);
|
||||
return ENOMEM;
|
||||
}
|
||||
dp->skb = skb;
|
||||
dp->dir = dir;
|
||||
dp->type = type;
|
||||
dp->port = port;
|
||||
dp->ifindex = skb->dev ? skb->dev->ifindex : 0;
|
||||
|
||||
spin_lock_irqsave(&pfk_divert_lock, flags);
|
||||
ds = NULL;
|
||||
list_for_each_entry(ds, &pfk_divert_list, link) {
|
||||
if (ds->port == port)
|
||||
break;
|
||||
}
|
||||
if (&ds->link == &pfk_divert_list) {
|
||||
pfk_divert_global.divs_noport++;
|
||||
spin_unlock_irqrestore(&pfk_divert_lock, flags);
|
||||
pr_info_ratelimited("pfk: divert port %u: no socket bound\n",
|
||||
port);
|
||||
pfk_divert_pkt_free(dp);
|
||||
return ENOENT;
|
||||
}
|
||||
if (ds->qlen >= ds->qspace) {
|
||||
ds->stats.divs_fullsock++;
|
||||
pfk_divert_global.divs_fullsock++;
|
||||
spin_unlock_irqrestore(&pfk_divert_lock, flags);
|
||||
pfk_divert_pkt_free(dp);
|
||||
return ENOBUFS;
|
||||
}
|
||||
spin_lock(&ds->lock);
|
||||
list_add_tail(&dp->node, &ds->q);
|
||||
ds->qlen++;
|
||||
ds->stats.divs_ipackets++;
|
||||
spin_unlock(&ds->lock);
|
||||
spin_unlock_irqrestore(&pfk_divert_lock, flags);
|
||||
|
||||
wake_up_interruptible(&ds->wq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern struct pf_divert *pf_find_divert(struct mbuf *);
|
||||
|
||||
void
|
||||
divert_packet(struct mbuf *m, int dir, u_int16_t divert_port)
|
||||
{
|
||||
pr_warn_ratelimited("pfk: divert v4 port %u: no divert socket layer (M6 pending), dropping\n",
|
||||
ntohs(divert_port));
|
||||
struct sk_buff *skb;
|
||||
int type = PF_DIVERT_TO;
|
||||
|
||||
if (!m)
|
||||
return;
|
||||
{
|
||||
struct pf_divert *dv = pf_find_divert(m);
|
||||
|
||||
if (dv)
|
||||
type = dv->type;
|
||||
}
|
||||
skb = m_to_skb(m);
|
||||
m->skb = NULL; /* ownership moves into the divert layer */
|
||||
m_freem(m);
|
||||
pfk_divert_queue(skb, dir, type, divert_port);
|
||||
}
|
||||
|
||||
void
|
||||
divert6_packet(struct mbuf *m, int dir, u_int16_t divert_port)
|
||||
{
|
||||
pr_warn_ratelimited("pfk: divert v6 port %u: no divert socket layer (M6 pending), dropping\n",
|
||||
ntohs(divert_port));
|
||||
m_freem(m);
|
||||
divert_packet(m, dir, divert_port);
|
||||
}
|
||||
|
||||
/* ---------------- socket ops ---------------- */
|
||||
|
||||
static int
|
||||
pfk_divert_create(struct net *net, struct socket *sock, int protocol, int kern)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct pfk_divert_sock *ds;
|
||||
|
||||
if (protocol != IPPROTO_DIVERT && protocol != 0)
|
||||
return -EPROTONOSUPPORT;
|
||||
if (sock->type != SOCK_RAW)
|
||||
return -ESOCKTNOSUPPORT;
|
||||
|
||||
ds = kzalloc(sizeof(*ds), GFP_KERNEL);
|
||||
if (!ds)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&ds->lock);
|
||||
init_waitqueue_head(&ds->wq);
|
||||
INIT_LIST_HEAD(&ds->link);
|
||||
INIT_LIST_HEAD(&ds->q);
|
||||
ds->qspace = 65536 + 100; /* BSD DIVERT_RECVSPACE */
|
||||
|
||||
sk = sk_alloc(net, PF_DIVERT_FAMILY, GFP_KERNEL, &pfk_divert_proto,
|
||||
kern);
|
||||
if (!sk) {
|
||||
kfree(ds);
|
||||
return -ENOMEM;
|
||||
}
|
||||
sock_init_data(sock, sk);
|
||||
sk->sk_user_data = ds;
|
||||
ds->sk = sk;
|
||||
sock->state = SS_UNCONNECTED;
|
||||
sock->ops = &pfk_divert_ops; /* forward decl below via struct */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pfk_divert_bind(struct socket *sock, struct sockaddr_unsized *uaddr,
|
||||
int addr_len)
|
||||
{
|
||||
struct pfk_divert_sock *ds = pfk_ds(sock->sk);
|
||||
unsigned long flags;
|
||||
|
||||
if (!ds)
|
||||
return -EINVAL;
|
||||
if (addr_len < (int)sizeof(struct sockaddr_in))
|
||||
return -EINVAL;
|
||||
|
||||
ds->port = ntohs(((struct sockaddr_in *)uaddr)->sin_port);
|
||||
if (ds->port == 0)
|
||||
return -EADDRNOTAVAIL; /* divert port 0 not allowed */
|
||||
|
||||
spin_lock_irqsave(&pfk_divert_lock, flags);
|
||||
if (!list_empty(&ds->link)) {
|
||||
spin_unlock_irqrestore(&pfk_divert_lock, flags);
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
list_add_tail(&ds->link, &pfk_divert_list);
|
||||
spin_unlock_irqrestore(&pfk_divert_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pfk_divert_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
int flags)
|
||||
{
|
||||
struct pfk_divert_sock *ds = pfk_ds(sock->sk);
|
||||
struct pfk_divert_pkt *dp;
|
||||
struct sk_buff *skb;
|
||||
unsigned long iflags;
|
||||
int copied;
|
||||
|
||||
if (!ds)
|
||||
return -EINVAL;
|
||||
if (msg_data_left(msg) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (;;) {
|
||||
spin_lock_irqsave(&ds->lock, iflags);
|
||||
if (!list_empty(&ds->q)) {
|
||||
dp = list_first_entry(&ds->q, struct pfk_divert_pkt,
|
||||
node);
|
||||
list_del_init(&dp->node);
|
||||
ds->qlen--;
|
||||
spin_unlock_irqrestore(&ds->lock, iflags);
|
||||
goto have;
|
||||
}
|
||||
spin_unlock_irqrestore(&ds->lock, iflags);
|
||||
if (flags & MSG_DONTWAIT ||
|
||||
READ_ONCE(sock->sk->sk_shutdown) != 0)
|
||||
return -EAGAIN;
|
||||
wait_event_interruptible(ds->wq,
|
||||
!list_empty(&ds->q) ||
|
||||
READ_ONCE(sock->sk->sk_shutdown) != 0);
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
have:
|
||||
skb = dp->skb;
|
||||
copied = min_t(size_t, len, skb->len);
|
||||
if (skb_copy_datagram_msg(skb, 0, msg, copied)) {
|
||||
pfk_divert_pkt_free(dp);
|
||||
return -EFAULT;
|
||||
}
|
||||
/* metadata as control data (BSD equivalent: sockaddr_div) */
|
||||
{
|
||||
struct cmsghdr *cm = CMSG_FIRSTHDR(msg);
|
||||
|
||||
if (cm && msg->msg_controllen >= sizeof(struct cmsghdr) + sizeof(int)) {
|
||||
msg->msg_controllen = 0; /* busybox-safe default */
|
||||
cm = NULL;
|
||||
}
|
||||
if (cm) {
|
||||
int ifindex = dp->ifindex;
|
||||
|
||||
cm->cmsg_level = SOL_SOCKET;
|
||||
cm->cmsg_type = PFDIVERT_CMSG_IFINDEX;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
memcpy(CMSG_DATA(cm), &ifindex, sizeof(ifindex));
|
||||
msg->msg_controllen = CMSG_SPACE(sizeof(int));
|
||||
}
|
||||
}
|
||||
sock_net_set(sock->sk, &init_net);
|
||||
ds->stats.divs_opackets++;
|
||||
pfk_divert_pkt_free(dp);
|
||||
return copied;
|
||||
}
|
||||
|
||||
/*
|
||||
* sendmsg: userspace hands the (possibly rewritten) packet back. The
|
||||
* ip header inside the bytes decides the flow; for PF_DIVERT_TO we inject
|
||||
* as input on the socket's last-recorded interface, otherwise we route.
|
||||
*/
|
||||
static int
|
||||
pfk_divert_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
||||
{
|
||||
struct pfk_divert_sock *ds = pfk_ds(sock->sk);
|
||||
struct sk_buff *skb;
|
||||
struct pf_ip *ip;
|
||||
int ifindex = 0;
|
||||
int type = PF_DIVERT_TO;
|
||||
struct cmsghdr *cm;
|
||||
|
||||
if (!ds)
|
||||
return -EINVAL;
|
||||
if (len > 65535)
|
||||
return -EMSGSIZE;
|
||||
|
||||
for (cm = CMSG_FIRSTHDR(msg); cm; cm = CMSG_NXTHDR(msg, cm)) {
|
||||
if (cm->cmsg_level != SOL_SOCKET)
|
||||
continue;
|
||||
if (cm->cmsg_type == PFDIVERT_CMSG_IFINDEX &&
|
||||
cm->cmsg_len >= CMSG_LEN(sizeof(int)))
|
||||
memcpy(&ifindex, CMSG_DATA(cm), sizeof(int));
|
||||
if (cm->cmsg_type == PFDIVERT_CMSG_TYPE &&
|
||||
cm->cmsg_len >= CMSG_LEN(sizeof(int)))
|
||||
memcpy(&type, CMSG_DATA(cm), sizeof(int));
|
||||
}
|
||||
|
||||
skb = alloc_skb(len + NET_SKB_PAD + NET_IP_ALIGN, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
|
||||
if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
|
||||
kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
|
||||
if (type == PF_DIVERT_TO) {
|
||||
/* deliver locally as if arrived on ifindex (default: last
|
||||
* ingress iface seen by this socket's queue) */
|
||||
struct net_device *dev = ifindex > 0 ?
|
||||
dev_get_by_index(&init_net, ifindex) : NULL;
|
||||
|
||||
if (dev) {
|
||||
skb->dev = dev;
|
||||
dev_put(dev);
|
||||
skb_reset_network_header(skb);
|
||||
/* netif_rx wants data at L3 */
|
||||
netif_rx(skb);
|
||||
return (int)len;
|
||||
}
|
||||
/* no device: route below */
|
||||
}
|
||||
|
||||
/* plain divert: route again (BSD divert_output -> ip_output) */
|
||||
if (pskb_may_pull(skb, sizeof(*ip))) {
|
||||
struct flowi4 fl4 = { };
|
||||
struct dst_entry *d;
|
||||
|
||||
ip = (struct pf_ip *)skb->data;
|
||||
fl4.daddr = ip->ip_dst.s_addr;
|
||||
fl4.saddr = ip->ip_src.s_addr;
|
||||
{
|
||||
struct rtable *rt = ip_route_output_key(&init_net,
|
||||
&fl4);
|
||||
|
||||
if (IS_ERR(rt))
|
||||
rt = NULL;
|
||||
d = rt ? &rt->dst : NULL;
|
||||
}
|
||||
if (d) {
|
||||
skb_dst_set(skb, d);
|
||||
skb_reset_network_header(skb);
|
||||
if (!skb->dev)
|
||||
skb->dev = skb_dst(skb)->dev;
|
||||
d->output(&init_net, NULL, skb);
|
||||
return (int)len;
|
||||
}
|
||||
}
|
||||
kfree_skb(skb);
|
||||
ds->stats.divs_errors++;
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
|
||||
static int
|
||||
pfk_divert_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct pfk_divert_sock *ds;
|
||||
unsigned long flags;
|
||||
|
||||
if (!sk)
|
||||
return 0;
|
||||
ds = pfk_ds(sk);
|
||||
if (ds) {
|
||||
spin_lock_irqsave(&pfk_divert_lock, flags);
|
||||
if (!list_empty(&ds->link))
|
||||
list_del_init(&ds->link);
|
||||
spin_unlock_irqrestore(&pfk_divert_lock, flags);
|
||||
while (!list_empty(&ds->q)) {
|
||||
struct pfk_divert_pkt *dp = list_first_entry(&ds->q,
|
||||
struct pfk_divert_pkt, node);
|
||||
|
||||
list_del_init(&dp->node);
|
||||
pfk_divert_pkt_free(dp);
|
||||
}
|
||||
kfree(ds);
|
||||
sk->sk_user_data = NULL;
|
||||
}
|
||||
sock_orphan(sk);
|
||||
sock_put(sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __poll_t
|
||||
pfk_divert_poll(struct file *file, struct socket *sock,
|
||||
poll_table *wait)
|
||||
{
|
||||
struct pfk_divert_sock *ds = pfk_ds(sock->sk);
|
||||
__poll_t mask = 0;
|
||||
|
||||
if (ds)
|
||||
poll_wait(file, &ds->wq, wait);
|
||||
else
|
||||
sock_poll_wait(file, sock, wait);
|
||||
if (ds && !list_empty(&ds->q))
|
||||
mask |= EPOLLIN | EPOLLRDNORM;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int
|
||||
pfk_divert_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct pfk_divert_sock *ds = pfk_ds(sock->sk);
|
||||
|
||||
if (!ds)
|
||||
return -EINVAL;
|
||||
switch (cmd) {
|
||||
case 3: { /* DIVERTCTL_STATS-ish: export queue stats */
|
||||
struct pfk_divert_stat st;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ds->lock, flags);
|
||||
st = ds->stats;
|
||||
spin_unlock_irqrestore(&ds->lock, flags);
|
||||
if (copy_to_user((void __user *)arg, &st, sizeof(st)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct proto_ops pfk_divert_ops = {
|
||||
.family = PF_DIVERT_FAMILY,
|
||||
.owner = THIS_MODULE,
|
||||
.release = pfk_divert_release,
|
||||
.bind = pfk_divert_bind,
|
||||
.connect = sock_no_connect,
|
||||
.socketpair = sock_no_socketpair,
|
||||
.accept = sock_no_accept,
|
||||
.getname = sock_no_getname,
|
||||
.poll = pfk_divert_poll,
|
||||
.ioctl = pfk_divert_ioctl,
|
||||
.listen = sock_no_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.sendmsg = pfk_divert_sendmsg,
|
||||
.recvmsg = pfk_divert_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
};
|
||||
|
||||
static const struct net_proto_family pfk_divert_family = {
|
||||
.family = PF_DIVERT_FAMILY,
|
||||
.create = pfk_divert_create,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
int
|
||||
pfk_divert_sock_register(void)
|
||||
{
|
||||
return sock_register(&pfk_divert_family);
|
||||
}
|
||||
|
||||
void
|
||||
pfk_divert_sock_unregister(void)
|
||||
{
|
||||
sock_unregister(PF_DIVERT_FAMILY);
|
||||
}
|
||||
@@ -360,6 +360,8 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
else
|
||||
ke->pfrke_fb = PFR_FB_NONE;
|
||||
}
|
||||
pr_info("pfkD: add_addrs ke af=%d p=%p q=%p\n",
|
||||
ke->pfrke_af, (void *)p, (void *)q);
|
||||
if (p == NULL && q == NULL) {
|
||||
if (pfr_route_kentry(tmpkt, ke)) {
|
||||
/* defer destroy after feedback is processed */
|
||||
@@ -1931,6 +1933,9 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
if (error)
|
||||
return (error);
|
||||
rs = pf_find_ruleset(tbl->pfrt_anchor);
|
||||
pr_info("pfkD: ina_define name=%s anchor=%s size=%d flags=%x rs=%p topen=%d tticket=%u ticket=%u\n",
|
||||
tbl->pfrt_name, tbl->pfrt_anchor, size, flags, (void *)rs,
|
||||
rs ? rs->topen : -1, rs ? rs->tticket : 0, ticket);
|
||||
if (rs == NULL || !rs->topen || ticket != rs->tticket)
|
||||
return (EBUSY);
|
||||
tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
|
||||
@@ -1978,12 +1983,16 @@ _skip:
|
||||
senderr(EFAULT);
|
||||
if (pfr_validate_addr(&ad))
|
||||
senderr(EINVAL);
|
||||
pr_info("pfkD: ina_define addr[%d] af=%d net=%d flags=%llx ifindex=%d\n",
|
||||
i, ad.pfra_af, ad.pfra_net, (unsigned long long)ad.pfra_flags,
|
||||
ad.pfra_ifindex);
|
||||
if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
|
||||
continue;
|
||||
p = pfr_create_kentry(&ad);
|
||||
if (p == NULL)
|
||||
senderr(ENOMEM);
|
||||
if (pfr_route_kentry(shadow, p)) {
|
||||
pr_info("pfkD: ina_define route failed\n");
|
||||
pfr_destroy_kentry(p);
|
||||
continue;
|
||||
}
|
||||
@@ -2000,6 +2009,8 @@ _skip:
|
||||
pfr_insert_ktables(&tableq);
|
||||
shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
|
||||
xaddr : NO_ADDRESSES;
|
||||
pr_info("pfkD: ina_define done xadd=%d xaddr=%d shadow_cnt=%d\n",
|
||||
xadd, xaddr, shadow->pfrkt_cnt);
|
||||
kt->pfrkt_shadow = shadow;
|
||||
} else {
|
||||
pfr_clean_node_mask(shadow, &addrq);
|
||||
@@ -2066,7 +2077,13 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
|
||||
return (EBUSY);
|
||||
|
||||
SLIST_INIT(&workq);
|
||||
pr_info("pfkD: ina_commit name=%s anchor=%s ticket=%u\n",
|
||||
trs->pfrt_name, trs->pfrt_anchor, ticket);
|
||||
RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
|
||||
pr_info("pfkD: ina_commit cand name=%s flags=%x inactive=%d shadow=%p\n",
|
||||
p->pfrkt_t.pfrt_name, p->pfrkt_flags,
|
||||
!!(p->pfrkt_flags & PFR_TFLAG_INACTIVE),
|
||||
(void *)p->pfrkt_shadow);
|
||||
if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
|
||||
pfr_skip_table(trs, p, 0))
|
||||
continue;
|
||||
@@ -2098,6 +2115,10 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero)
|
||||
struct pfr_ktable *shadow = kt->pfrkt_shadow;
|
||||
int nflags;
|
||||
|
||||
pr_info("pfkD: commit_ktable name=%s flags=%x shadow_cnt=%d\n",
|
||||
kt->pfrkt_t.pfrt_name, kt->pfrkt_flags,
|
||||
shadow ? shadow->pfrkt_cnt : -1);
|
||||
|
||||
if (shadow->pfrkt_cnt == NO_ADDRESSES) {
|
||||
if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
|
||||
pfr_clstats_ktable(kt, tzero, 1);
|
||||
|
||||
@@ -96,6 +96,8 @@ static struct miscdevice pfk_dev = {
|
||||
|
||||
extern void pf_status_init(void);
|
||||
extern int pfattach(int);
|
||||
extern int pfk_divert_sock_register(void);
|
||||
extern void pfk_divert_sock_unregister(void);
|
||||
|
||||
static void
|
||||
pfk_pfi_event(int added, struct pfk_ifnet *ifp)
|
||||
@@ -134,15 +136,20 @@ static int __init pfk_init(void)
|
||||
pfattach(0);
|
||||
pfk_if_set_event_cb(pfk_pfi_event);
|
||||
pfk_if_iterate(pfk_pfi_attach_one);
|
||||
err = pfk_hooks_register();
|
||||
err = pfk_divert_sock_register();
|
||||
if (err)
|
||||
goto err_if;
|
||||
err = pfk_hooks_register();
|
||||
if (err)
|
||||
goto err_divert;
|
||||
err = misc_register(&pfk_dev);
|
||||
if (err)
|
||||
goto err_hooks;
|
||||
pr_info("pfk: PF-on-Linux engine loaded (OpenBSD 8.0 base)\n");
|
||||
return 0;
|
||||
err_hooks:
|
||||
pfk_divert_sock_unregister();
|
||||
err_divert:
|
||||
pfk_hooks_unregister();
|
||||
err_if:
|
||||
pfk_if_exit();
|
||||
@@ -161,6 +168,7 @@ static void __exit pfk_exit(void)
|
||||
* self-rearms (pf_purge re-arms on every run) and would keep the
|
||||
* workqueues non-empty forever (observed rmmod hang). */
|
||||
misc_deregister(&pfk_dev);
|
||||
pfk_divert_sock_unregister();
|
||||
pfk_net_lock();
|
||||
pf_status.running = 0;
|
||||
pfk_net_unlock();
|
||||
|
||||
Reference in new issue
Block a user