mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-22 02:37:15 +00:00
pfctl: fix incorrect mask on dynamic address
A PF rule using an IPv4 address followed by an IPv6 address and then a dynamic address, e.g. "pass from {192.0.2.1 2001:db8::1} to (pppoe0)", will have an incorrect /32 mask applied to the dynamic address. MFC after: 3 weeks Obtained from: OpenBSD See also: https://ftp.openbsd.org/pub/OpenBSD/patches/5.6/common/007_pfctl.patch.sig Sponsored by: Rubicon Communications, LLC ("Netgate") Event: Oslo Hackathon at Modirum
This commit is contained in:
parent
a5bebe4359
commit
7ce98cf2f8
|
@ -4720,6 +4720,10 @@ natrule : nataction interface af proto fromto tag tagged rtable
|
|||
remove_invalid_hosts(&$9->host, &r.af);
|
||||
if (invalid_redirect($9->host, r.af))
|
||||
YYERROR;
|
||||
if ($9->host->addr.type == PF_ADDR_DYNIFTL) {
|
||||
if (($9->host = gen_dynnode($9->host, r.af)) == NULL)
|
||||
err(1, "calloc");
|
||||
}
|
||||
if (check_netmask($9->host, r.af))
|
||||
YYERROR;
|
||||
|
||||
|
@ -4936,6 +4940,10 @@ binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag
|
|||
yyerror("binat ip versions must match");
|
||||
YYERROR;
|
||||
}
|
||||
if ($8->addr.type == PF_ADDR_DYNIFTL) {
|
||||
if (($8 = gen_dynnode($8, binat.af)) == NULL)
|
||||
err(1, "calloc");
|
||||
}
|
||||
if (check_netmask($8, binat.af))
|
||||
YYERROR;
|
||||
memcpy(&binat.src.addr, &$8->addr,
|
||||
|
@ -4951,6 +4959,10 @@ binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag
|
|||
yyerror("binat ip versions must match");
|
||||
YYERROR;
|
||||
}
|
||||
if ($9->addr.type == PF_ADDR_DYNIFTL) {
|
||||
if (($9 = gen_dynnode($9, binat.af)) == NULL)
|
||||
err(1, "calloc");
|
||||
}
|
||||
if (check_netmask($9, binat.af))
|
||||
YYERROR;
|
||||
memcpy(&binat.dst.addr, &$9->addr,
|
||||
|
@ -4980,6 +4992,10 @@ binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag
|
|||
"a single address");
|
||||
YYERROR;
|
||||
}
|
||||
if ($13->host->addr.type == PF_ADDR_DYNIFTL) {
|
||||
if (($13->host = gen_dynnode($13->host, binat.af)) == NULL)
|
||||
err(1, "calloc");
|
||||
}
|
||||
if (check_netmask($13->host, binat.af))
|
||||
YYERROR;
|
||||
|
||||
|
@ -5982,7 +5998,7 @@ expand_rule(struct pfctl_rule *r,
|
|||
char tagname[PF_TAG_NAME_SIZE];
|
||||
char match_tagname[PF_TAG_NAME_SIZE];
|
||||
struct pf_pooladdr *pa;
|
||||
struct node_host *h;
|
||||
struct node_host *h, *osrch, *odsth;
|
||||
u_int8_t flags, flagset, keep_state;
|
||||
|
||||
memcpy(label, r->label, sizeof(r->label));
|
||||
|
@ -6043,6 +6059,18 @@ expand_rule(struct pfctl_rule *r,
|
|||
sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
|
||||
errx(1, "expand_rule: strlcpy");
|
||||
|
||||
osrch = odsth = NULL;
|
||||
if (src_host->addr.type == PF_ADDR_DYNIFTL) {
|
||||
osrch = src_host;
|
||||
if ((src_host = gen_dynnode(src_host, r->af)) == NULL)
|
||||
err(1, "expand_rule: calloc");
|
||||
}
|
||||
if (dst_host->addr.type == PF_ADDR_DYNIFTL) {
|
||||
odsth = dst_host;
|
||||
if ((dst_host = gen_dynnode(dst_host, r->af)) == NULL)
|
||||
err(1, "expand_rule: calloc");
|
||||
}
|
||||
|
||||
error += check_netmask(src_host, r->af);
|
||||
error += check_netmask(dst_host, r->af);
|
||||
|
||||
|
@ -6121,6 +6149,15 @@ expand_rule(struct pfctl_rule *r,
|
|||
added++;
|
||||
}
|
||||
|
||||
if (osrch && src_host->addr.type == PF_ADDR_DYNIFTL) {
|
||||
free(src_host);
|
||||
src_host = osrch;
|
||||
}
|
||||
if (odsth && dst_host->addr.type == PF_ADDR_DYNIFTL) {
|
||||
free(dst_host);
|
||||
dst_host = odsth;
|
||||
}
|
||||
|
||||
))))))))));
|
||||
|
||||
FREE_LIST(struct node_if, interfaces);
|
||||
|
|
|
@ -1306,16 +1306,12 @@ int
|
|||
check_netmask(struct node_host *h, sa_family_t af)
|
||||
{
|
||||
struct node_host *n = NULL;
|
||||
struct pf_addr *m;
|
||||
struct pf_addr *m;
|
||||
|
||||
for (n = h; n != NULL; n = n->next) {
|
||||
if (h->addr.type == PF_ADDR_TABLE)
|
||||
continue;
|
||||
m = &h->addr.v.a.mask;
|
||||
/* fix up netmask for dynaddr */
|
||||
if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
|
||||
unmask(m, AF_INET6) > 32)
|
||||
set_ipmask(n, 32);
|
||||
/* netmasks > 32 bit are invalid on v4 */
|
||||
if (af == AF_INET &&
|
||||
(m->addr32[1] || m->addr32[2] || m->addr32[3])) {
|
||||
|
@ -1327,6 +1323,30 @@ check_netmask(struct node_host *h, sa_family_t af)
|
|||
return (0);
|
||||
}
|
||||
|
||||
struct node_host *
|
||||
gen_dynnode(struct node_host *h, sa_family_t af)
|
||||
{
|
||||
struct node_host *n;
|
||||
struct pf_addr *m;
|
||||
|
||||
if (h->addr.type != PF_ADDR_DYNIFTL)
|
||||
return (NULL);
|
||||
|
||||
if ((n = calloc(1, sizeof(*n))) == NULL)
|
||||
return (NULL);
|
||||
bcopy(h, n, sizeof(*n));
|
||||
n->ifname = NULL;
|
||||
n->next = NULL;
|
||||
n->tail = NULL;
|
||||
|
||||
/* fix up netmask */
|
||||
m = &n->addr.v.a.mask;
|
||||
if (af == AF_INET && unmask(m, AF_INET6) > 32)
|
||||
set_ipmask(n, 32);
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
/* interface lookup routines */
|
||||
|
||||
static struct node_host *iftab;
|
||||
|
|
|
@ -360,6 +360,7 @@ extern const struct pf_timeout pf_timeouts[];
|
|||
void set_ipmask(struct node_host *, u_int8_t);
|
||||
int check_netmask(struct node_host *, sa_family_t);
|
||||
int unmask(struct pf_addr *, sa_family_t);
|
||||
struct node_host *gen_dynnode(struct node_host *, sa_family_t);
|
||||
void ifa_load(void);
|
||||
int get_query_socket(void);
|
||||
struct node_host *ifa_exists(char *);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
pass inet from 1.1.1.1 to (self) flags S/SA keep state
|
||||
pass inet6 from 2002:: to (self)/32 flags S/SA keep state
|
||||
pass inet6 from 2002:: to (self) flags S/SA keep state
|
||||
pass inet6 from 2002:: to (self) flags S/SA keep state
|
||||
pass inet from 1.1.1.1 to (self) flags S/SA keep state
|
||||
pass inet from 1.1.1.1 to (self) flags S/SA keep state
|
||||
pass inet6 from 2002:: to (self)/32 flags S/SA keep state
|
||||
pass inet6 from 2002:: to (self)/40 flags S/SA keep state
|
||||
pass inet6 from 2002:: to (self)/40 flags S/SA keep state
|
||||
pass inet from 1.1.1.1 to (self) flags S/SA keep state
|
||||
|
|
1
sbin/pfctl/tests/files/pf1018.in
Normal file
1
sbin/pfctl/tests/files/pf1018.in
Normal file
|
@ -0,0 +1 @@
|
|||
pass from { 192.0.2.1 2001:db8::1 } to (pppoe0)
|
2
sbin/pfctl/tests/files/pf1018.ok
Normal file
2
sbin/pfctl/tests/files/pf1018.ok
Normal file
|
@ -0,0 +1,2 @@
|
|||
pass inet from 192.0.2.1 to (pppoe0) flags S/SA keep state
|
||||
pass inet6 from 2001:db8::1 to (pppoe0) flags S/SA keep state
|
|
@ -126,3 +126,4 @@ PFCTL_TEST(1014, "Ethernet rule with one label")
|
|||
PFCTL_TEST(1015, "Ethernet rule with several labels")
|
||||
PFCTL_TEST(1016, "Ethernet rule with ridentifier and one label")
|
||||
PFCTL_TEST(1017, "Ethernet rule with ridentifier and several labels")
|
||||
PFCTL_TEST(1018, "Test dynamic address mask")
|
||||
|
|
Loading…
Reference in a new issue