Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/admin-guide/plugins/header_rewrite.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,14 @@ string. Therefore the condition is treated as if it were ::
which is true when the connection is not TLS. The arguments ``H2``, ``IPV4``, and ``IPV6`` work the
same way.

As a special matcher, the inbound IP addresses can be matched against a list of IP ranges, e.g.
::

cond %{INBOUND:REMOTE-ADDR} {192.168.201.0/24,10.0.0.0/8}

Note that this will not work against the non-IP based conditions, such as the protocol families,
and the configuration parser will error out. The format here is very specific, in particular no
white spaces are allowed between the ranges.

IP
~~
Expand All @@ -400,6 +408,13 @@ actually as a value to an operator, e.g. ::
set-header X-Server-IP %{IP:SERVER}
set-header X-Outbound-IP %{IP:OUTBOUND}

As a special matcher, the `IP` can be matched against a list of IP ranges, e.g.
::

cond %{IP:CLIENT} {192.168.201.0/24,10.0.0.0/8}

The format here is very specific, in particular no white spaces are allowed between the
ranges.

INTERNAL-TRANSACTION
~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 2 additions & 0 deletions plugins/header_rewrite/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ header_rewrite_header_rewrite_la_SOURCES = \
header_rewrite/operators.h \
header_rewrite/regex_helper.cc \
header_rewrite/regex_helper.h \
header_rewrite/ipranges_helper.cc \
header_rewrite/ipranges_helper.h \
header_rewrite/resources.cc \
header_rewrite/resources.h \
header_rewrite/ruleset.cc \
Expand Down
4 changes: 4 additions & 0 deletions plugins/header_rewrite/condition.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ parse_matcher_op(std::string &arg)
arg.erase(arg.length() - 1, arg.length());
return MATCH_REGULAR_EXPRESSION;
break;
case '{':
arg.erase(0, 1);
arg.erase(arg.length() - 1, arg.length());
return MATCH_IP_RANGES;
default:
return MATCH_EQUAL;
break;
Expand Down
95 changes: 79 additions & 16 deletions plugins/header_rewrite/conditions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,17 @@ ConditionIp::initialize(Parser &p)
{
Condition::initialize(p);

MatcherType *match = new MatcherType(_cond_op);
if (_cond_op == MATCH_IP_RANGES) { // Special hack for IP ranges for now ...
MatcherTypeIp *match = new MatcherTypeIp(_cond_op);

match->set(p.get_arg());
_matcher = match;
match->set(p.get_arg());
_matcher = match;
} else {
MatcherType *match = new MatcherType(_cond_op);

match->set(p.get_arg());
_matcher = match;
}
}

void
Expand All @@ -557,14 +564,39 @@ ConditionIp::set_qualifier(const std::string &q)
bool
ConditionIp::eval(const Resources &res)
{
std::string s;
if (_matcher->op() == MATCH_IP_RANGES) {
const sockaddr *addr = nullptr;

append_value(s, res);
bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);
switch (_ip_qual) {
case IP_QUAL_CLIENT:
addr = TSHttpTxnClientAddrGet(res.txnp);
break;
case IP_QUAL_INBOUND:
addr = TSHttpTxnIncomingAddrGet(res.txnp);
break;
case IP_QUAL_SERVER:
addr = TSHttpTxnServerAddrGet(res.txnp);
break;
case IP_QUAL_OUTBOUND:
addr = TSHttpTxnOutgoingAddrGet(res.txnp);
break;
}

if (addr) {
return static_cast<const Matchers<const sockaddr *> *>(_matcher)->test(addr);
} else {
return false;
}
} else {
std::string s;

TSDebug(PLUGIN_NAME, "Evaluating IP(): %s - rval: %d", s.c_str(), rval);
append_value(s, res);
bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);

return rval;
TSDebug(PLUGIN_NAME, "Evaluating IP(): %s - rval: %d", s.c_str(), rval);

return rval;
}
}

void
Expand Down Expand Up @@ -1029,10 +1061,17 @@ ConditionInbound::initialize(Parser &p)
{
Condition::initialize(p);

MatcherType *match = new MatcherType(_cond_op);
if (_cond_op == MATCH_IP_RANGES) { // Special hack for IP ranges for now ...
MatcherTypeIp *match = new MatcherTypeIp(_cond_op);

match->set(p.get_arg());
_matcher = match;
match->set(p.get_arg());
_matcher = match;
} else {
MatcherType *match = new MatcherType(_cond_op);

match->set(p.get_arg());
_matcher = match;
}
}

void
Expand Down Expand Up @@ -1070,14 +1109,38 @@ ConditionInbound::set_qualifier(const std::string &q)
bool
ConditionInbound::eval(const Resources &res)
{
std::string s;
// Special hack for IP-Ranges since we really don't need to do a string conversion for the comparison.
if (_matcher->op() == MATCH_IP_RANGES) {
const sockaddr *addr = nullptr;

append_value(s, res);
bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);
switch (_net_qual) {
case NET_QUAL_LOCAL_ADDR:
addr = TSHttpTxnIncomingAddrGet(res.txnp);
break;
case NET_QUAL_REMOTE_ADDR:
addr = TSHttpTxnClientAddrGet(res.txnp);
break;
default:
// Only support actual IP addresses of course...
TSError("[%s] %%{%s:%s} is not supported, only IP-Addresses allowed", PLUGIN_NAME, TAG, get_qualifier().c_str());
break;
}

if (addr) {
return static_cast<const Matchers<const sockaddr *> *>(_matcher)->test(addr);
} else {
return false;
}
} else {
std::string s;

TSDebug(PLUGIN_NAME, "Evaluating %s(): %s - rval: %d", TAG, s.c_str(), rval);
append_value(s, res);
bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);

return rval;
TSDebug(PLUGIN_NAME, "Evaluating %s(): %s - rval: %d", TAG, s.c_str(), rval);

return rval;
}
}

void
Expand Down
6 changes: 4 additions & 2 deletions plugins/header_rewrite/conditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ class ConditionInternalTxn : public Condition
class ConditionIp : public Condition
{
typedef Matchers<std::string> MatcherType;
typedef Matchers<const sockaddr *> MatcherTypeIp;

public:
explicit ConditionIp() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionIp"); };
Expand Down Expand Up @@ -503,8 +504,9 @@ class ConditionCidr : public Condition
/// Information about the inbound (client) session.
class ConditionInbound : public Condition
{
using MatcherType = Matchers<std::string>;
using self = ConditionInbound;
using MatcherType = Matchers<std::string>;
using MatcherTypeIp = Matchers<const sockaddr *>;
using self = ConditionInbound;

public:
explicit ConditionInbound() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionInbound"); };
Expand Down
43 changes: 43 additions & 0 deletions plugins/header_rewrite/ipranges_helper.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ipranges_helper.h"
#include "tscpp/util/TextView.h"

#include <vector>

bool
ipRangesHelper::addIpRanges(const std::string &s)
{
ts::TextView src{s};

while (src) {
IpAddr start, end;

if (TS_SUCCESS == ats_ip_range_parse(src.take_prefix_at(','), start, end)) {
_ipRanges.mark(start, end);
}
}

if (_ipRanges.count() > 0) {
TSDebug(PLUGIN_NAME, " Added %zu IP ranges while parsing", _ipRanges.count());
return true;
} else {
TSDebug(PLUGIN_NAME, " No IP ranges added, possibly bad input");
return false;
}
}
46 changes: 46 additions & 0 deletions plugins/header_rewrite/ipranges_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once

#include "tscore/IpMap.h"
#include "tscore/ink_inet.h"

#include "ts/ts.h"

#include "lulu.h"

#include <string>

class ipRangesHelper
{
public:
~ipRangesHelper() {}

bool addIpRanges(const std::string &s);

bool
ipRangesMatch(const sockaddr *addr) const
{
void *ptr = nullptr;

return _ipRanges.contains(addr, &ptr);
}

private:
IpMap _ipRanges;
};
57 changes: 54 additions & 3 deletions plugins/header_rewrite/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "ts/ts.h"

#include "regex_helper.h"
#include "ipranges_helper.h"
#include "lulu.h"

// Possible operators that we support (at least partially)
Expand All @@ -36,6 +37,7 @@ enum MatcherOps {
MATCH_LESS_THEN,
MATCH_GREATER_THEN,
MATCH_REGULAR_EXPRESSION,
MATCH_IP_RANGES,
};

///////////////////////////////////////////////////////////////////////////////
Expand All @@ -51,6 +53,12 @@ class Matcher
Matcher(const Matcher &) = delete;
void operator=(const Matcher &) = delete;

MatcherOps
op() const
{
return _op;
}

protected:
const MatcherOps _op;
};
Expand All @@ -70,7 +78,7 @@ template <class T> class Matchers : public Matcher
void
setRegex(const std::string & /* data ATS_UNUSED */)
{
if (!helper.setRegexMatch(_data)) {
if (!reHelper.setRegexMatch(_data)) {
std::stringstream ss;
ss << _data;
TSError("[%s] Invalid regex: failed to precompile: %s", PLUGIN_NAME, ss.str().c_str());
Expand Down Expand Up @@ -118,6 +126,11 @@ template <class T> class Matchers : public Matcher
case MATCH_REGULAR_EXPRESSION:
return test_reg(t);
break;
case MATCH_IP_RANGES:
// This is an error, the Matcher doesn't make sense to match on IP ranges
TSError("[%s] Invalid matcher: MATCH_IP_RANGES", PLUGIN_NAME);
throw std::runtime_error("Can not match on IP ranges");
break;
default:
// ToDo: error
break;
Expand Down Expand Up @@ -189,13 +202,51 @@ template <class T> class Matchers : public Matcher
int ovector[OVECCOUNT];

TSDebug(PLUGIN_NAME, "Test regular expression %s : %s", _data.c_str(), t.c_str());
if (helper.regexMatch(t.c_str(), t.length(), ovector) > 0) {
if (reHelper.regexMatch(t.c_str(), t.length(), ovector) > 0) {
TSDebug(PLUGIN_NAME, "Successfully found regular expression match");
return true;
}
return false;
}

T _data;
regexHelper helper;
regexHelper reHelper;
};

// Specialized case matcher for the IP addresses matches.
// ToDo: we should specialize the regex matcher as well.
template <> class Matchers<const sockaddr *> : public Matcher
{
public:
explicit Matchers<const sockaddr *>(const MatcherOps op) : Matcher(op) {}

void
set(const std::string &data)
{
if (!ipHelper.addIpRanges(data)) {
TSError("[%s] Invalid IP-range: failed to parse: %s", PLUGIN_NAME, data.c_str());
TSDebug(PLUGIN_NAME, "Invalid IP-range: failed to parse: %s", data.c_str());
throw std::runtime_error("Malformed IP-range");
} else {
TSDebug(PLUGIN_NAME, "IP-range precompiled successfully");
}
}

bool
test(const sockaddr *addr) const
{
if (ipHelper.ipRangesMatch(addr) > 0) {
if (TSIsDebugTagSet(PLUGIN_NAME)) {
char text[INET6_ADDRSTRLEN];

TSDebug(PLUGIN_NAME, "Successfully found IP-range match on %s", getIP(addr, text));
}
return true;
} else {
return false;
}
}

private:
ipRangesHelper ipHelper;
};
Loading