mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-18 02:19:39 +00:00
pf: allow filtering on the receive interface
add support to pf for filtering a packet by the interface it was received on. use the received-on IFNAME filter option on a pf.conf rule to restrict which packet the interface had to be received on. eg: pass out on em0 from $foo to $bar received-on fxp0 ive been running this in production for a week now. i find it particularly usefull with interface groups. no objections, and a few "i like"s from henning, claudio, deraadt, mpf Obtained from: OpenBSD, dlg <dlg@openbsd.org>, 95b4320893 Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D46577
This commit is contained in:
parent
50ecaf1bd4
commit
2339ead638
@ -1252,6 +1252,7 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct
|
||||
|
||||
snl_add_msg_attr_uid(nw, PF_RT_UID, &r->uid);
|
||||
snl_add_msg_attr_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&r->gid);
|
||||
snl_add_msg_attr_string(nw, PF_RT_RCV_IFNAME, r->rcv_ifname);
|
||||
|
||||
snl_add_msg_attr_u32(nw, PF_RT_RULE_FLAG, r->rule_flag);
|
||||
snl_add_msg_attr_u8(nw, PF_RT_ACTION, r->action);
|
||||
@ -1656,6 +1657,7 @@ static struct snl_attr_parser ap_getrule[] = {
|
||||
{ .type = PF_RT_STATES_TOTAL, .off = _OUT(r.states_tot), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_RT_SRC_NODES, .off = _OUT(r.src_nodes), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_RT_ANCHOR_CALL, .off = _OUT(anchor_call), .arg = (void*)MAXPATHLEN, .cb = snl_attr_copy_string },
|
||||
{ .type = PF_RT_RCV_IFNAME, .off = _OUT(r.rcv_ifname), .arg = (void*)IFNAMSIZ, .cb = snl_attr_copy_string },
|
||||
};
|
||||
static struct snl_field_parser fp_getrule[] = {};
|
||||
#undef _OUT
|
||||
|
@ -220,6 +220,7 @@ struct pfctl_rule {
|
||||
|
||||
struct pf_rule_uid uid;
|
||||
struct pf_rule_gid gid;
|
||||
char rcv_ifname[IFNAMSIZ];
|
||||
|
||||
uint32_t rule_flag;
|
||||
uint8_t action;
|
||||
|
@ -241,6 +241,7 @@ static struct filter_opts {
|
||||
#define FOM_FRAGCACHE 0x8000 /* does not exist in OpenBSD */
|
||||
struct node_uid *uid;
|
||||
struct node_gid *gid;
|
||||
struct node_if *rcv;
|
||||
struct {
|
||||
u_int8_t b1;
|
||||
u_int8_t b2;
|
||||
@ -367,7 +368,7 @@ void expand_rule(struct pfctl_rule *, struct node_if *,
|
||||
struct node_host *, struct node_proto *, struct node_os *,
|
||||
struct node_host *, struct node_port *, struct node_host *,
|
||||
struct node_port *, struct node_uid *, struct node_gid *,
|
||||
struct node_icmp *, const char *);
|
||||
struct node_if *, struct node_icmp *, const char *);
|
||||
int expand_altq(struct pf_altq *, struct node_if *,
|
||||
struct node_queue *, struct node_queue_bw bwspec,
|
||||
struct node_queue_opt *);
|
||||
@ -516,7 +517,7 @@ int parseport(char *, struct range *r, int);
|
||||
%token STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
|
||||
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW
|
||||
%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
|
||||
%token DIVERTTO DIVERTREPLY BRIDGE_TO
|
||||
%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON
|
||||
%token <v.string> STRING
|
||||
%token <v.number> NUMBER
|
||||
%token <v.i> PORTBINARY
|
||||
@ -1073,7 +1074,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
|
||||
|
||||
expand_rule(&r, $5, NULL, $7, $8.src_os,
|
||||
$8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
|
||||
$9.uid, $9.gid, $9.icmpspec,
|
||||
$9.uid, $9.gid, $9.rcv, $9.icmpspec,
|
||||
pf->astack[pf->asd + 1] ? pf->alast->name : $2);
|
||||
free($2);
|
||||
pf->astack[pf->asd + 1] = NULL;
|
||||
@ -1096,7 +1097,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
|
||||
|
||||
expand_rule(&r, $3, NULL, $5, $6.src_os,
|
||||
$6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
|
||||
0, 0, 0, $2);
|
||||
0, 0, 0, 0, $2);
|
||||
free($2);
|
||||
}
|
||||
| RDRANCHOR string interface af proto fromto rtable {
|
||||
@ -1138,7 +1139,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
|
||||
|
||||
expand_rule(&r, $3, NULL, $5, $6.src_os,
|
||||
$6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
|
||||
0, 0, 0, $2);
|
||||
0, 0, 0, 0, $2);
|
||||
free($2);
|
||||
}
|
||||
| BINATANCHOR string interface af proto fromto rtable {
|
||||
@ -1461,7 +1462,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
|
||||
|
||||
expand_rule(&r, $4, NULL, $6, $7.src_os,
|
||||
$7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
|
||||
NULL, NULL, NULL, "");
|
||||
NULL, NULL, NULL, NULL, "");
|
||||
}
|
||||
;
|
||||
|
||||
@ -1626,7 +1627,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
|
||||
if (h != NULL)
|
||||
expand_rule(&r, j, NULL, NULL, NULL, h,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, "");
|
||||
NULL, NULL, "");
|
||||
|
||||
if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
|
||||
bzero(&r, sizeof(r));
|
||||
@ -1648,7 +1649,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
|
||||
if (h != NULL)
|
||||
expand_rule(&r, NULL, NULL,
|
||||
NULL, NULL, h, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, "");
|
||||
NULL, NULL, NULL, NULL, NULL, "");
|
||||
} else
|
||||
free(hh);
|
||||
}
|
||||
@ -2802,7 +2803,7 @@ pfrule : action dir logquick interface route af proto fromto
|
||||
|
||||
expand_rule(&r, $4, $5.host, $7, $8.src_os,
|
||||
$8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
|
||||
$9.uid, $9.gid, $9.icmpspec, "");
|
||||
$9.uid, $9.gid, $9.rcv, $9.icmpspec, "");
|
||||
}
|
||||
;
|
||||
|
||||
@ -2937,6 +2938,13 @@ filter_opt : USER uids {
|
||||
filter_opts.match_tag = $3;
|
||||
filter_opts.match_tag_not = $1;
|
||||
}
|
||||
| RECEIVEDON if_item {
|
||||
if (filter_opts.rcv) {
|
||||
yyerror("cannot respecify received-on");
|
||||
YYERROR;
|
||||
}
|
||||
filter_opts.rcv = $2;
|
||||
}
|
||||
| PROBABILITY probability {
|
||||
double p;
|
||||
|
||||
@ -4882,7 +4890,7 @@ natrule : nataction interface af proto fromto tag tagged rtable
|
||||
|
||||
expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
|
||||
$5.src_os, $5.src.host, $5.src.port, $5.dst.host,
|
||||
$5.dst.port, 0, 0, 0, "");
|
||||
$5.dst.port, 0, 0, 0, 0, "");
|
||||
free($9);
|
||||
}
|
||||
;
|
||||
@ -6034,8 +6042,8 @@ expand_rule(struct pfctl_rule *r,
|
||||
struct node_proto *protos, struct node_os *src_oses,
|
||||
struct node_host *src_hosts, struct node_port *src_ports,
|
||||
struct node_host *dst_hosts, struct node_port *dst_ports,
|
||||
struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
|
||||
const char *anchor_call)
|
||||
struct node_uid *uids, struct node_gid *gids, struct node_if *rcv,
|
||||
struct node_icmp *icmp_types, const char *anchor_call)
|
||||
{
|
||||
sa_family_t af = r->af;
|
||||
int added = 0, error = 0;
|
||||
@ -6138,6 +6146,10 @@ expand_rule(struct pfctl_rule *r,
|
||||
r->gid.op = gid->op;
|
||||
r->gid.gid[0] = gid->gid[0];
|
||||
r->gid.gid[1] = gid->gid[1];
|
||||
if (rcv) {
|
||||
strlcpy(r->rcv_ifname, rcv->ifname,
|
||||
sizeof(r->rcv_ifname));
|
||||
}
|
||||
r->type = icmp_type->type;
|
||||
r->code = icmp_type->code;
|
||||
|
||||
@ -6381,6 +6393,7 @@ lookup(char *s)
|
||||
{ "rdr-anchor", RDRANCHOR},
|
||||
{ "realtime", REALTIME},
|
||||
{ "reassemble", REASSEMBLE},
|
||||
{ "received-on", RECEIVEDON},
|
||||
{ "reply-to", REPLYTO},
|
||||
{ "require-order", REQUIREORDER},
|
||||
{ "return", RETURN},
|
||||
|
@ -960,6 +960,8 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
|
||||
}
|
||||
print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
|
||||
verbose, numeric);
|
||||
if (r->rcv_ifname[0])
|
||||
printf(" received-on %s", r->rcv_ifname);
|
||||
if (r->uid.op)
|
||||
print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
|
||||
UID_MAX);
|
||||
|
@ -776,6 +776,7 @@ struct pf_krule {
|
||||
char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
|
||||
uint32_t ridentifier;
|
||||
char ifname[IFNAMSIZ];
|
||||
char rcv_ifname[IFNAMSIZ];
|
||||
char qname[PF_QNAME_SIZE];
|
||||
char pqname[PF_QNAME_SIZE];
|
||||
char tagname[PF_TAG_NAME_SIZE];
|
||||
@ -792,6 +793,7 @@ struct pf_krule {
|
||||
time_t *timestamp;
|
||||
|
||||
struct pfi_kkif *kif;
|
||||
struct pfi_kkif *rcv_kif;
|
||||
struct pf_kanchor *anchor;
|
||||
struct pfr_ktable *overload_tbl;
|
||||
|
||||
|
@ -375,6 +375,7 @@ static void pf_patch_8(struct mbuf *, u_int16_t *, u_int8_t *, u_int8_t,
|
||||
static struct pf_kstate *pf_find_state(struct pfi_kkif *,
|
||||
const struct pf_state_key_cmp *, u_int);
|
||||
static int pf_src_connlimit(struct pf_kstate **);
|
||||
static int pf_match_rcvif(struct mbuf *, struct pf_krule *);
|
||||
static void pf_overload_task(void *v, int pending);
|
||||
static u_short pf_insert_src_node(struct pf_ksrc_node **,
|
||||
struct pf_krule *, struct pf_addr *, sa_family_t);
|
||||
@ -3951,6 +3952,27 @@ pf_match_tag(struct mbuf *m, struct pf_krule *r, int *tag, int mtag)
|
||||
(r->match_tag_not && r->match_tag != *tag));
|
||||
}
|
||||
|
||||
static int
|
||||
pf_match_rcvif(struct mbuf *m, struct pf_krule *r)
|
||||
{
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct pfi_kkif *kif;
|
||||
|
||||
if (ifp == NULL)
|
||||
return (0);
|
||||
|
||||
kif = (struct pfi_kkif *)ifp->if_pf_kif;
|
||||
|
||||
if (kif == NULL) {
|
||||
DPFPRINTF(PF_DEBUG_URGENT,
|
||||
("pf_test_via: kif == NULL, @%d via %s\n", r->nr,
|
||||
r->rcv_ifname));
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (pfi_kkif_match(r->rcv_kif, kif));
|
||||
}
|
||||
|
||||
int
|
||||
pf_tag_packet(struct mbuf *m, struct pf_pdesc *pd, int tag)
|
||||
{
|
||||
@ -5155,6 +5177,8 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif,
|
||||
else if (r->match_tag && !pf_match_tag(m, r, &tag,
|
||||
pd->pf_mtag ? pd->pf_mtag->tag : 0))
|
||||
r = TAILQ_NEXT(r, entries);
|
||||
else if (r->rcv_kif && !pf_match_rcvif(m, r))
|
||||
r = TAILQ_NEXT(r, entries);
|
||||
else if (r->os_fingerprint != PF_OSFP_ANY &&
|
||||
(pd->proto != IPPROTO_TCP || !pf_osfp_match(
|
||||
pf_osfp_fingerprint(pd, m, off, th),
|
||||
|
@ -603,6 +603,8 @@ pf_free_rule(struct pf_krule *rule)
|
||||
pfr_detach_table(rule->overload_tbl);
|
||||
if (rule->kif)
|
||||
pfi_kkif_unref(rule->kif);
|
||||
if (rule->rcv_kif)
|
||||
pfi_kkif_unref(rule->rcv_kif);
|
||||
pf_kanchor_remove(rule);
|
||||
pf_empty_kpool(&rule->rpool.list);
|
||||
|
||||
@ -1306,6 +1308,7 @@ pf_hash_rule_rolling(MD5_CTX *ctx, struct pf_krule *rule)
|
||||
for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
|
||||
PF_MD5_UPD_STR(rule, label[i]);
|
||||
PF_MD5_UPD_STR(rule, ifname);
|
||||
PF_MD5_UPD_STR(rule, rcv_ifname);
|
||||
PF_MD5_UPD_STR(rule, match_tagname);
|
||||
PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
|
||||
PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
|
||||
@ -2068,7 +2071,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
|
||||
struct pf_kruleset *ruleset;
|
||||
struct pf_krule *tail;
|
||||
struct pf_kpooladdr *pa;
|
||||
struct pfi_kkif *kif = NULL;
|
||||
struct pfi_kkif *kif = NULL, *rcv_kif = NULL;
|
||||
int rs_num;
|
||||
int error = 0;
|
||||
|
||||
@ -2081,6 +2084,8 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
|
||||
|
||||
if (rule->ifname[0])
|
||||
kif = pf_kkif_create(M_WAITOK);
|
||||
if (rule->rcv_ifname[0])
|
||||
rcv_kif = pf_kkif_create(M_WAITOK);
|
||||
pf_counter_u64_init(&rule->evaluations, M_WAITOK);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
pf_counter_u64_init(&rule->packets[i], M_WAITOK);
|
||||
@ -2143,6 +2148,13 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
|
||||
} else
|
||||
rule->kif = NULL;
|
||||
|
||||
if (rule->rcv_ifname[0]) {
|
||||
rule->rcv_kif = pfi_kkif_attach(rcv_kif, rule->rcv_ifname);
|
||||
rcv_kif = NULL;
|
||||
pfi_kkif_ref(rule->rcv_kif);
|
||||
} else
|
||||
rule->rcv_kif = NULL;
|
||||
|
||||
if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
|
||||
error = EBUSY;
|
||||
|
||||
@ -2242,6 +2254,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
|
||||
PF_RULES_WUNLOCK();
|
||||
PF_CONFIG_UNLOCK();
|
||||
errout_unlocked:
|
||||
pf_kkif_free(rcv_kif);
|
||||
pf_kkif_free(kif);
|
||||
pf_krule_free(rule);
|
||||
return (error);
|
||||
|
@ -730,6 +730,7 @@ static const struct nlattr_parser nla_p_rule[] = {
|
||||
{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
|
||||
{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
|
||||
{ .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
|
||||
{ .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
|
||||
};
|
||||
NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
|
||||
#undef _OUT
|
||||
@ -941,6 +942,8 @@ pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||
nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
|
||||
nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
|
||||
|
||||
nlattr_add_string(nw, PF_RT_RCV_IFNAME, rule->rcv_ifname);
|
||||
|
||||
nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
|
||||
nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
|
||||
nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
|
||||
|
@ -257,6 +257,7 @@ enum pf_rule_type_t {
|
||||
PF_RT_STATES_TOTAL = 70, /* u64 */
|
||||
PF_RT_SRC_NODES = 71, /* u64 */
|
||||
PF_RT_ANCHOR_CALL = 72, /* string */
|
||||
PF_RT_RCV_IFNAME = 73, /* string */
|
||||
};
|
||||
|
||||
enum pf_addrule_type_t {
|
||||
|
Loading…
Reference in New Issue
Block a user