Skip to content

Commit

Permalink
Fix the conffile parser to parse RHS literals as prefix types when th…
Browse files Browse the repository at this point in the history
…e LHS is an IPv4 address or IPv6 address
  • Loading branch information
arr2036 committed Dec 1, 2014
1 parent f8a7cda commit 29f6821
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/include/tmpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, value_pair_tmpl_t **out, char const *n

void tmpl_free(value_pair_tmpl_t **tmpl);

bool tmpl_cast_in_place(value_pair_tmpl_t *vpt, DICT_ATTR const *da);
bool tmpl_cast_in_place(value_pair_tmpl_t *vpt, PW_TYPE type, DICT_ATTR const *enumv);

void tmpl_cast_in_place_str(value_pair_tmpl_t *vpt);

Expand Down
2 changes: 0 additions & 2 deletions src/lib/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,6 @@ size_t vp_data_prints_value(char *out, size_t outlen,

size_t len = 0, freespace = outlen;

fr_assert(!enumv || (enumv->type == type));

if (!data) return 0;
if (outlen == 0) return inlen;

Expand Down
4 changes: 2 additions & 2 deletions src/main/modcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1790,7 +1790,7 @@ int modcall_fixup_update(value_pair_map_t *map, UNUSED void *ctx)
(cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
tmpl_cast_in_place_str(map->rhs);
} else {
if (!tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da)) {
if (!tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da)) {
cf_log_err(map->ci, "%s", fr_strerror());
return -1;
}
Expand Down Expand Up @@ -3620,7 +3620,7 @@ bool modcall_pass2(modcallable *mc)
if (f->vpt->type == TMPL_TYPE_ATTR) {
rad_assert(f->vpt->tmpl_da != NULL);

if (!tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da)) {
if (!tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da)) {
cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
fr_strerror());
return false;
Expand Down
29 changes: 25 additions & 4 deletions src/main/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
* Cast it to the appropriate data type.
*/
if ((c->data.map->lhs->type == TMPL_TYPE_LITERAL) &&
!tmpl_cast_in_place(c->data.map->lhs, c->cast)) {
!tmpl_cast_in_place(c->data.map->lhs, c->cast->type, c->cast)) {
*error = "Failed to parse field";
if (lhs) talloc_free(lhs);
if (rhs) talloc_free(rhs);
Expand All @@ -754,7 +754,7 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
*/
if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
(c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
!tmpl_cast_in_place(c->data.map->rhs, c->cast)) {
!tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast)) {
return_rhs("Failed to parse field");
}

Expand Down Expand Up @@ -950,17 +950,38 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
* literal. Cast the RHS to the type of the cast.
*/
if (c->cast && (c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
!tmpl_cast_in_place(c->data.map->rhs, c->cast)) {
!tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast)) {
return_rhs("Failed to parse field");
}

/*
* The LHS is an attribute, and the RHS is a literal. Cast the
* RHS to the data type of the LHS.
*
* Note: There's a hack in here to always parse RHS as the
* equivalent prefix type if the LHS is an IP address.
*
* This allows Framed-IP-Address < 192.168.0.0./24
*/
if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
(c->data.map->rhs->type == TMPL_TYPE_LITERAL)) {
if (!tmpl_cast_in_place(c->data.map->rhs, c->data.map->lhs->tmpl_da)) {
PW_TYPE type;

switch (c->data.map->lhs->tmpl_da->type) {
case PW_TYPE_IPV4_ADDR:
type = PW_TYPE_IPV4_PREFIX;
break;

case PW_TYPE_IPV6_ADDR:
type = PW_TYPE_IPV6_PREFIX;
break;

default:
type = c->data.map->lhs->tmpl_da->type;
break;
}

if (!tmpl_cast_in_place(c->data.map->rhs, type, c->data.map->lhs->tmpl_da)) {
DICT_ATTR const *da = c->data.map->lhs->tmpl_da;

if ((da->vendor == 0) &&
Expand Down
10 changes: 5 additions & 5 deletions src/main/tmpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1315,25 +1315,25 @@ ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, value_pair_tmpl_t **out, char const *nam
/** Convert a tmpl containing literal data, to the type specified by da.
*
* @param[in,out] vpt the template to modify
* @param[in] da the dictionary attribute to cast it to
* @param[in] type to case to.
* @param[in] enumv Enumerated dictionary values.
* @return true for success, false for failure.
*/
bool tmpl_cast_in_place(value_pair_tmpl_t *vpt, DICT_ATTR const *da)
bool tmpl_cast_in_place(value_pair_tmpl_t *vpt, PW_TYPE type, DICT_ATTR const *enumv)
{
ssize_t ret;

VERIFY_TMPL(vpt);

rad_assert(vpt != NULL);
rad_assert(da != NULL);
rad_assert(vpt->type == TMPL_TYPE_LITERAL);

vpt->tmpl_data_type = da->type;
vpt->tmpl_data_type = type;

/*
* Why do we pass a pointer to the tmpl type? Goddamn WiMAX.
*/
ret = value_data_from_str(vpt, &vpt->tmpl_data_value, &vpt->tmpl_data_type, da, vpt->name, vpt->len);
ret = value_data_from_str(vpt, &vpt->tmpl_data_value, &vpt->tmpl_data_type, enumv, vpt->name, vpt->len);
if (ret < 0) return false;

vpt->type = TMPL_TYPE_DATA;
Expand Down
7 changes: 7 additions & 0 deletions src/tests/keywords/ipprefix
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ update reply {
update control {
Tmp-Cast-IPv4Prefix := 198.51.100.255/16
Tmp-Cast-IPv6Prefix := ::198.51.100.255/112
Framed-IP-Address := 198.51.0.1
}

if ("%{control:Tmp-Cast-IPv6Prefix}" != '::198.51.0.0/112') {
Expand Down Expand Up @@ -43,3 +44,9 @@ if (!(&control:Tmp-Cast-IPv4Prefix < 198.0.0.0/8)) {
Filter-Id += "Fail 4"
}
}

if (!(&control:Framed-IP-Address < 198.51.0.0/16)) {
update reply {
Filter-Id += "Fail 5"
}
}

0 comments on commit 29f6821

Please sign in to comment.