Add support to IPFW for classification based on "diverted" status
(that is, input via a divert socket).
This commit is contained in:
parent
5599f1b52b
commit
6daf7ebd28
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=136073
@ -217,6 +217,9 @@ enum tokens {
|
|||||||
TOK_KEEPSTATE,
|
TOK_KEEPSTATE,
|
||||||
TOK_LAYER2,
|
TOK_LAYER2,
|
||||||
TOK_OUT,
|
TOK_OUT,
|
||||||
|
TOK_DIVERTED,
|
||||||
|
TOK_DIVERTEDLOOPBACK,
|
||||||
|
TOK_DIVERTEDOUTPUT,
|
||||||
TOK_XMIT,
|
TOK_XMIT,
|
||||||
TOK_RECV,
|
TOK_RECV,
|
||||||
TOK_VIA,
|
TOK_VIA,
|
||||||
@ -325,6 +328,9 @@ struct _s_x rule_options[] = {
|
|||||||
{ "bridged", TOK_LAYER2 },
|
{ "bridged", TOK_LAYER2 },
|
||||||
{ "layer2", TOK_LAYER2 },
|
{ "layer2", TOK_LAYER2 },
|
||||||
{ "out", TOK_OUT },
|
{ "out", TOK_OUT },
|
||||||
|
{ "diverted", TOK_DIVERTED },
|
||||||
|
{ "diverted-loopback", TOK_DIVERTEDLOOPBACK },
|
||||||
|
{ "diverted-output", TOK_DIVERTEDOUTPUT },
|
||||||
{ "xmit", TOK_XMIT },
|
{ "xmit", TOK_XMIT },
|
||||||
{ "recv", TOK_RECV },
|
{ "recv", TOK_RECV },
|
||||||
{ "via", TOK_VIA },
|
{ "via", TOK_VIA },
|
||||||
@ -1302,6 +1308,23 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
|||||||
printf(cmd->len & F_NOT ? " out" : " in");
|
printf(cmd->len & F_NOT ? " out" : " in");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case O_DIVERTED:
|
||||||
|
switch (cmd->arg1) {
|
||||||
|
case 3:
|
||||||
|
printf(" diverted");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf(" diverted-loopback");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf(" diverted-output");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf(" diverted-?<%u>", cmd->arg1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case O_LAYER2:
|
case O_LAYER2:
|
||||||
printf(" layer2");
|
printf(" layer2");
|
||||||
break;
|
break;
|
||||||
@ -3360,6 +3383,18 @@ add(int ac, char *av[])
|
|||||||
fill_cmd(cmd, O_IN, 0, 0);
|
fill_cmd(cmd, O_IN, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_DIVERTED:
|
||||||
|
fill_cmd(cmd, O_DIVERTED, 0, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DIVERTEDLOOPBACK:
|
||||||
|
fill_cmd(cmd, O_DIVERTED, 0, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DIVERTEDOUTPUT:
|
||||||
|
fill_cmd(cmd, O_DIVERTED, 0, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_FRAG:
|
case TOK_FRAG:
|
||||||
fill_cmd(cmd, O_FRAG, 0, 0);
|
fill_cmd(cmd, O_FRAG, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <netinet/ip_divert.h>
|
#include <netinet/ip_divert.h>
|
||||||
#include <netinet/ip_var.h>
|
#include <netinet/ip_var.h>
|
||||||
|
#include <netinet/ip_fw.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Divert sockets
|
* Divert sockets
|
||||||
@ -268,6 +269,8 @@ static int
|
|||||||
div_output(struct socket *so, struct mbuf *m,
|
div_output(struct socket *so, struct mbuf *m,
|
||||||
struct sockaddr_in *sin, struct mbuf *control)
|
struct sockaddr_in *sin, struct mbuf *control)
|
||||||
{
|
{
|
||||||
|
struct m_tag *mtag;
|
||||||
|
struct divert_tag *dt;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
|
KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
|
||||||
@ -275,23 +278,22 @@ div_output(struct socket *so, struct mbuf *m,
|
|||||||
if (control)
|
if (control)
|
||||||
m_freem(control); /* XXX */
|
m_freem(control); /* XXX */
|
||||||
|
|
||||||
|
mtag = m_tag_get(PACKET_TAG_DIVERT,
|
||||||
|
sizeof(struct divert_tag), M_NOWAIT);
|
||||||
|
if (mtag == NULL) {
|
||||||
|
error = ENOBUFS;
|
||||||
|
goto cantsend;
|
||||||
|
}
|
||||||
|
dt = (struct divert_tag *)(mtag+1);
|
||||||
|
dt->info = 0;
|
||||||
|
dt->cookie = 0;
|
||||||
|
m_tag_prepend(m, mtag);
|
||||||
|
|
||||||
/* Loopback avoidance and state recovery */
|
/* Loopback avoidance and state recovery */
|
||||||
if (sin) {
|
if (sin) {
|
||||||
struct m_tag *mtag;
|
|
||||||
struct divert_tag *dt;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mtag = m_tag_get(PACKET_TAG_DIVERT,
|
|
||||||
sizeof(struct divert_tag), M_NOWAIT);
|
|
||||||
if (mtag == NULL) {
|
|
||||||
error = ENOBUFS;
|
|
||||||
goto cantsend;
|
|
||||||
}
|
|
||||||
dt = (struct divert_tag *)(mtag+1);
|
|
||||||
dt->info = 0;
|
|
||||||
dt->cookie = sin->sin_port;
|
dt->cookie = sin->sin_port;
|
||||||
m_tag_prepend(m, mtag);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find receive interface with the given name, stuffed
|
* Find receive interface with the given name, stuffed
|
||||||
* (if it exists) in the sin_zero[] field.
|
* (if it exists) in the sin_zero[] field.
|
||||||
@ -309,6 +311,7 @@ div_output(struct socket *so, struct mbuf *m,
|
|||||||
struct ip *const ip = mtod(m, struct ip *);
|
struct ip *const ip = mtod(m, struct ip *);
|
||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
|
|
||||||
|
dt->info |= IP_FW_DIVERT_OUTPUT_FLAG;
|
||||||
INP_INFO_WLOCK(&divcbinfo);
|
INP_INFO_WLOCK(&divcbinfo);
|
||||||
inp = sotoinpcb(so);
|
inp = sotoinpcb(so);
|
||||||
INP_LOCK(inp);
|
INP_LOCK(inp);
|
||||||
@ -341,6 +344,7 @@ div_output(struct socket *so, struct mbuf *m,
|
|||||||
INP_UNLOCK(inp);
|
INP_UNLOCK(inp);
|
||||||
INP_INFO_WUNLOCK(&divcbinfo);
|
INP_INFO_WUNLOCK(&divcbinfo);
|
||||||
} else {
|
} else {
|
||||||
|
dt->info |= IP_FW_DIVERT_LOOPBACK_FLAG;
|
||||||
if (m->m_pkthdr.rcvif == NULL) {
|
if (m->m_pkthdr.rcvif == NULL) {
|
||||||
/*
|
/*
|
||||||
* No luck with the name, check by IP address.
|
* No luck with the name, check by IP address.
|
||||||
|
@ -135,6 +135,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
|||||||
O_ANTISPOOF, /* none */
|
O_ANTISPOOF, /* none */
|
||||||
O_JAIL, /* u32 = id */
|
O_JAIL, /* u32 = id */
|
||||||
O_ALTQ, /* u32 = altq classif. qid */
|
O_ALTQ, /* u32 = altq classif. qid */
|
||||||
|
O_DIVERTED, /* arg1=bitmap (1:loop, 2:out) */
|
||||||
|
|
||||||
O_LAST_OPCODE /* not an opcode! */
|
O_LAST_OPCODE /* not an opcode! */
|
||||||
};
|
};
|
||||||
@ -415,9 +416,11 @@ typedef struct _ipfw_table {
|
|||||||
*/
|
*/
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|
||||||
#define IP_FW_PORT_DYNT_FLAG 0x10000
|
#define IP_FW_PORT_DYNT_FLAG 0x00010000
|
||||||
#define IP_FW_PORT_TEE_FLAG 0x20000
|
#define IP_FW_PORT_TEE_FLAG 0x00020000
|
||||||
#define IP_FW_PORT_DENY_FLAG 0x40000
|
#define IP_FW_PORT_DENY_FLAG 0x00040000
|
||||||
|
#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000
|
||||||
|
#define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arguments for calling ipfw_chk() and dummynet_io(). We put them
|
* Arguments for calling ipfw_chk() and dummynet_io(). We put them
|
||||||
|
@ -1717,6 +1717,14 @@ ipfw_chk(struct ip_fw_args *args)
|
|||||||
struct ip_fw_ugid fw_ugid_cache;
|
struct ip_fw_ugid fw_ugid_cache;
|
||||||
int ugid_lookup = 0;
|
int ugid_lookup = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* divinput_flags If non-zero, set to the IP_FW_DIVERT_*_FLAG
|
||||||
|
* associated with a packet input on a divert socket. This
|
||||||
|
* will allow to distinguish traffic and its direction when
|
||||||
|
* it originates from a divert socket.
|
||||||
|
*/
|
||||||
|
u_int divinput_flags = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* oif | args->oif If NULL, ipfw_chk has been called on the
|
* oif | args->oif If NULL, ipfw_chk has been called on the
|
||||||
* inbound path (ether_input, bdg_forward, ip_input).
|
* inbound path (ether_input, bdg_forward, ip_input).
|
||||||
@ -1893,8 +1901,11 @@ ipfw_chk(struct ip_fw_args *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* reset divert rule to avoid confusion later */
|
/* reset divert rule to avoid confusion later */
|
||||||
if (mtag)
|
if (mtag) {
|
||||||
|
divinput_flags = divert_info(mtag) &
|
||||||
|
(IP_FW_DIVERT_OUTPUT_FLAG | IP_FW_DIVERT_LOOPBACK_FLAG);
|
||||||
m_tag_delete(m, mtag);
|
m_tag_delete(m, mtag);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now scan the rules, and parse microinstructions for each rule.
|
* Now scan the rules, and parse microinstructions for each rule.
|
||||||
@ -2027,6 +2038,13 @@ ipfw_chk(struct ip_fw_args *args)
|
|||||||
match = (args->eh != NULL);
|
match = (args->eh != NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case O_DIVERTED:
|
||||||
|
match = (cmd->arg1 & 1 && divinput_flags &
|
||||||
|
IP_FW_DIVERT_LOOPBACK_FLAG) ||
|
||||||
|
(cmd->arg1 & 2 && divinput_flags &
|
||||||
|
IP_FW_DIVERT_OUTPUT_FLAG);
|
||||||
|
break;
|
||||||
|
|
||||||
case O_PROTO:
|
case O_PROTO:
|
||||||
/*
|
/*
|
||||||
* We do not allow an arg of 0 so the
|
* We do not allow an arg of 0 so the
|
||||||
@ -2912,6 +2930,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
|
|||||||
case O_LAYER2:
|
case O_LAYER2:
|
||||||
case O_IN:
|
case O_IN:
|
||||||
case O_FRAG:
|
case O_FRAG:
|
||||||
|
case O_DIVERTED:
|
||||||
case O_IPOPT:
|
case O_IPOPT:
|
||||||
case O_IPTOS:
|
case O_IPTOS:
|
||||||
case O_IPPRECEDENCE:
|
case O_IPPRECEDENCE:
|
||||||
|
Loading…
Reference in New Issue
Block a user