fix: skb->mark masks were multi-bit (IN mark matched OUT test) - transit traffic never reached the out ruleset; ingress/egress interface groups; pfctl resolves (egress) pool locally
This commit is contained in:
1 parent
c449e01b9a
commit
9c3c4b6bbc
3 files changed
+85
-3
No files matched your search
@@ -7,7 +7,7 @@
|
|||||||
long pfk_ioctl(struct file *f, unsigned int cmd, unsigned long addr);
|
long pfk_ioctl(struct file *f, unsigned int cmd, unsigned long addr);
|
||||||
int pfk_enable(int on);
|
int pfk_enable(int on);
|
||||||
void pfk_status(struct pf_status *s);
|
void pfk_status(struct pf_status *s);
|
||||||
#define PFK_SKIP_PF 0x50460040u /* skb->mark: reinjected, bypass pf */
|
#define PFK_SKIP_PF 0x00000004u /* skb->mark: reinjected, bypass pf */
|
||||||
|
|
||||||
int pfk_hooks_register(void);
|
int pfk_hooks_register(void);
|
||||||
void pfk_hooks_unregister(void);
|
void pfk_hooks_unregister(void);
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ struct pfk_pkt {
|
|||||||
int dir;
|
int dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PFK_DONE_IN 0x50460010u /* skb->mark bit: PF_IN pass completed */
|
#define PFK_DONE_IN 0x00000001u /* skb->mark bit: PF_IN pass completed */
|
||||||
#define PFK_DONE_OUT 0x50460020u /* skb->mark bit: PF_OUT pass completed */
|
#define PFK_DONE_OUT 0x00000002u /* skb->mark bit: PF_OUT pass completed */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pfk_pkt_reinject(struct pfk_pkt *pk)
|
pfk_pkt_reinject(struct pfk_pkt *pk)
|
||||||
|
|||||||
@@ -1562,6 +1562,84 @@ ifa_exists(const char *ifa_name)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PFLINUX: interface group emulation.
|
||||||
|
*
|
||||||
|
* OpenBSD creates the "ingress" and "egress" interface groups (ifgroups)
|
||||||
|
* and pfctl expands "(egress)" in a pool into the addresses of the group
|
||||||
|
* members via the SIOCGIFGMEMB socket ioctl. Linux has neither ifgroups
|
||||||
|
* nor that ioctl, so resolve the two groups locally:
|
||||||
|
*
|
||||||
|
* egress -> the interface of the default route (the same interface the
|
||||||
|
* kernel module marks as the pf "egress" interface)
|
||||||
|
* ingress -> every non-loopback interface
|
||||||
|
*/
|
||||||
|
static struct node_host *
|
||||||
|
ifa_group_members(const char *group, int flags)
|
||||||
|
{
|
||||||
|
struct node_host *n, *h = NULL, *c;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
socklen_t slen = sizeof(sin);
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if (iftab == NULL)
|
||||||
|
ifa_load();
|
||||||
|
|
||||||
|
if (!strcmp(group, "egress")) {
|
||||||
|
/* source address of the default route */
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(9);
|
||||||
|
sin.sin_addr.s_addr = htonl(0x01010101); /* discard route */
|
||||||
|
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) != -1) {
|
||||||
|
if (connect(s, (struct sockaddr *)&sin,
|
||||||
|
sizeof(sin)) == 0 &&
|
||||||
|
getsockname(s, (struct sockaddr *)&sin, &slen) == 0) {
|
||||||
|
close(s);
|
||||||
|
for (n = iftab; n; n = n->next) {
|
||||||
|
if (n->af != AF_INET)
|
||||||
|
continue;
|
||||||
|
if (n->addr.v.a.addr.v4.s_addr !=
|
||||||
|
sin.sin_addr.s_addr)
|
||||||
|
continue;
|
||||||
|
if ((c = calloc(1, sizeof(*c))) == NULL)
|
||||||
|
err(1, "calloc");
|
||||||
|
*c = *n;
|
||||||
|
c->next = NULL;
|
||||||
|
c->tail = c;
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "ingress" and any other group: every non-loopback interface */
|
||||||
|
for (n = iftab; n; n = n->next) {
|
||||||
|
if (n->af == AF_LINK)
|
||||||
|
continue;
|
||||||
|
if (n->ifa_flags & IFF_LOOPBACK)
|
||||||
|
continue;
|
||||||
|
if ((flags & PFI_AFLAG_BROADCAST) && n->af != AF_INET)
|
||||||
|
continue;
|
||||||
|
if ((c = calloc(1, sizeof(*c))) == NULL)
|
||||||
|
err(1, "calloc");
|
||||||
|
*c = *n;
|
||||||
|
c->next = NULL;
|
||||||
|
c->tail = c;
|
||||||
|
if (h == NULL)
|
||||||
|
h = c;
|
||||||
|
else {
|
||||||
|
h->tail->next = c;
|
||||||
|
h->tail = c->tail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (h);
|
||||||
|
}
|
||||||
|
|
||||||
struct node_host *
|
struct node_host *
|
||||||
ifa_grouplookup(const char *ifa_name, int flags)
|
ifa_grouplookup(const char *ifa_name, int flags)
|
||||||
{
|
{
|
||||||
@@ -1576,6 +1654,10 @@ ifa_grouplookup(const char *ifa_name, int flags)
|
|||||||
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
|
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
|
||||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
|
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
|
||||||
close(s);
|
close(s);
|
||||||
|
/* PFLINUX: interface group emulation (see above) */
|
||||||
|
if (!strcmp(ifa_name, "ingress") ||
|
||||||
|
!strcmp(ifa_name, "egress"))
|
||||||
|
return (ifa_group_members(ifa_name, flags));
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user