Add support to IPFW for classification based on "diverted" status
(that is, input via a divert socket).
This commit is contained in:
parent
4454a09917
commit
4f70622005
@ -217,6 +217,9 @@ enum tokens {
|
||||
TOK_KEEPSTATE,
|
||||
TOK_LAYER2,
|
||||
TOK_OUT,
|
||||
TOK_DIVERTED,
|
||||
TOK_DIVERTEDLOOPBACK,
|
||||
TOK_DIVERTEDOUTPUT,
|
||||
TOK_XMIT,
|
||||
TOK_RECV,
|
||||
TOK_VIA,
|
||||
@ -325,6 +328,9 @@ struct _s_x rule_options[] = {
|
||||
{ "bridged", TOK_LAYER2 },
|
||||
{ "layer2", TOK_LAYER2 },
|
||||
{ "out", TOK_OUT },
|
||||
{ "diverted", TOK_DIVERTED },
|
||||
{ "diverted-loopback", TOK_DIVERTEDLOOPBACK },
|
||||
{ "diverted-output", TOK_DIVERTEDOUTPUT },
|
||||
{ "xmit", TOK_XMIT },
|
||||
{ "recv", TOK_RECV },
|
||||
{ "via", TOK_VIA },
|
||||
@ -1302,6 +1308,23 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
||||
printf(cmd->len & F_NOT ? " out" : " in");
|
||||
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:
|
||||
printf(" layer2");
|
||||
break;
|
||||
@ -3360,6 +3383,18 @@ add(int ac, char *av[])
|
||||
fill_cmd(cmd, O_IN, 0, 0);
|
||||
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:
|
||||
fill_cmd(cmd, O_FRAG, 0, 0);
|
||||
break;
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
|
||||
/*
|
||||
* Divert sockets
|
||||
@ -268,6 +269,8 @@ static int
|
||||
div_output(struct socket *so, struct mbuf *m,
|
||||
struct sockaddr_in *sin, struct mbuf *control)
|
||||
{
|
||||
struct m_tag *mtag;
|
||||
struct divert_tag *dt;
|
||||
int error = 0;
|
||||
|
||||
KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
|
||||
@ -275,23 +278,22 @@ div_output(struct socket *so, struct mbuf *m,
|
||||
if (control)
|
||||
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 */
|
||||
if (sin) {
|
||||
struct m_tag *mtag;
|
||||
struct divert_tag *dt;
|
||||
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;
|
||||
m_tag_prepend(m, mtag);
|
||||
|
||||
/*
|
||||
* Find receive interface with the given name, stuffed
|
||||
* (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 inpcb *inp;
|
||||
|
||||
dt->info |= IP_FW_DIVERT_OUTPUT_FLAG;
|
||||
INP_INFO_WLOCK(&divcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
INP_LOCK(inp);
|
||||
@ -341,6 +344,7 @@ div_output(struct socket *so, struct mbuf *m,
|
||||
INP_UNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&divcbinfo);
|
||||
} else {
|
||||
dt->info |= IP_FW_DIVERT_LOOPBACK_FLAG;
|
||||
if (m->m_pkthdr.rcvif == NULL) {
|
||||
/*
|
||||
* No luck with the name, check by IP address.
|
||||
|
@ -135,6 +135,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
||||
O_ANTISPOOF, /* none */
|
||||
O_JAIL, /* u32 = id */
|
||||
O_ALTQ, /* u32 = altq classif. qid */
|
||||
O_DIVERTED, /* arg1=bitmap (1:loop, 2:out) */
|
||||
|
||||
O_LAST_OPCODE /* not an opcode! */
|
||||
};
|
||||
@ -415,9 +416,11 @@ typedef struct _ipfw_table {
|
||||
*/
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define IP_FW_PORT_DYNT_FLAG 0x10000
|
||||
#define IP_FW_PORT_TEE_FLAG 0x20000
|
||||
#define IP_FW_PORT_DENY_FLAG 0x40000
|
||||
#define IP_FW_PORT_DYNT_FLAG 0x00010000
|
||||
#define IP_FW_PORT_TEE_FLAG 0x00020000
|
||||
#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
|
||||
|
@ -1717,6 +1717,14 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
struct ip_fw_ugid fw_ugid_cache;
|
||||
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
|
||||
* 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 */
|
||||
if (mtag)
|
||||
if (mtag) {
|
||||
divinput_flags = divert_info(mtag) &
|
||||
(IP_FW_DIVERT_OUTPUT_FLAG | IP_FW_DIVERT_LOOPBACK_FLAG);
|
||||
m_tag_delete(m, mtag);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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:
|
||||
/*
|
||||
* 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_IN:
|
||||
case O_FRAG:
|
||||
case O_DIVERTED:
|
||||
case O_IPOPT:
|
||||
case O_IPTOS:
|
||||
case O_IPPRECEDENCE:
|
||||
|
Loading…
Reference in New Issue
Block a user