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
33 changes: 24 additions & 9 deletions doc/admin-guide/files/ip_allow.config.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ ip_allow.config
.. configfile:: ip_allow.config

The :file:`ip_allow.config` file controls client access to the Traffic
Server proxy cache. You can specify ranges of IP addresses that are
allowed to use the Traffic Server as a web proxy cache. After you modify
the :file:`ip_allow.config` file, navigate to the Traffic Server bin
directory and run the :option:`traffic_ctl config reload` command to apply changes. When
Server proxy cache and Traffic Server connections to the servers. You
can specify ranges of IP addresses that are allowed to use the Traffic
Server as a web proxy cache or that are allowed to be remapped by
Traffic Server. After you modify the :file:`ip_allow.config` file,
navigate to the Traffic Server bin directory and run the
:option:`traffic_ctl config reload` command to apply changes. When
you apply the changes to a node in a cluster, Traffic Server
automatically applies the changes to all other nodes in the cluster.

Expand All @@ -36,13 +38,18 @@ Each line in the :file:`ip_allow.config` file must have the following
format::

src_ip=<range of IP addresses> action=<action> [method=<list of methods separated by '|'>]
dest_ip=<range of IP addresses> action=<action> [method=<list of methods separated by '|'>]

where src_ip is the IP address or range of IP addresses of the
client(s). The action ``ip_allow`` enables the specified client(s) to
access the Traffic Server proxy cache, and ``ip_deny`` denies the
specified client(s) to access the Traffic Server proxy cache. Multiple
method keywords can be specified (method=GET method=HEAD), or multiple
methods can be separated by an '\|' (method=GET\|HEAD). The method
client(s) and dest_ip is the IP address or range of IP addresses of the
server(s). When src_ip is indicated, the action ``ip_allow`` enables
the specified client(s) to access the Traffic Server proxy cache,
and ``ip_deny`` denies the specified client(s) to access the Traffic
Server proxy cache. When dest_ip is indicated, the action ``ip_allow``
enables the Traffic Server to access the specified server(s), and
``ip_deny`` denies the Traffic Server to access the specified server(s).
Multiple method keywords can be specified (method=GET method=HEAD), or
multiple methods can be separated by an '\|' (method=GET\|HEAD). The method
keyword is optional and it is defaulted to ALL. This supports ANY string
as the HTTP method, meaning no validation is done to check whether it
is a valid HTTP method. This allows you to create filters for any method
Expand Down Expand Up @@ -78,3 +85,11 @@ the Traffic Server proxy cache::

src_ip=123.45.6.0-123.45.6.123 action=ip_deny

The following example enables the Traffic Server to access all servers::

dest_ip=0.0.0.0-255.255.255.255 action=ip_allow

The following example denies the Traffic Server to access all servers
on a specific subnet::

dest_ip=10.0.0.0-10.0.0.255 action=ip_deny
4 changes: 2 additions & 2 deletions iocore/net/SessionAccept.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ SessionAccept::testIpAllowPolicy(sockaddr const *client_ip)
IpAllow::scoped_config ipallow;
const AclRecord *acl_record = nullptr;
if (ipallow) {
acl_record = ipallow->match(client_ip);
if (acl_record && acl_record->isEmpty()) {
acl_record = ipallow->match(client_ip, IpAllow::SRC_ADDR);
if (acl_record && acl_record->isEmpty() && ipallow->isAcceptCheckEnabled()) {
acl_record = nullptr;
}
}
Expand Down
4 changes: 3 additions & 1 deletion lib/ts/MatcherUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,9 @@ processDurationString(char *str, int *seconds)

const matcher_tags http_dest_tags = {"dest_host", "dest_domain", "dest_ip", "url_regex", "url", "host_regex", true};

const matcher_tags ip_allow_tags = {nullptr, nullptr, "src_ip", nullptr, nullptr, nullptr, false};
const matcher_tags ip_allow_src_tags = {nullptr, nullptr, "src_ip", nullptr, nullptr, nullptr, false};

const matcher_tags ip_allow_dest_tags = {nullptr, nullptr, "dest_ip", nullptr, nullptr, nullptr, true};

const matcher_tags socks_server_tags = {nullptr, nullptr, "dest_ip", nullptr, nullptr, nullptr, false};

Expand Down
3 changes: 2 additions & 1 deletion lib/ts/MatcherUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ struct matcher_tags {
};

extern const matcher_tags http_dest_tags;
extern const matcher_tags ip_allow_tags;
extern const matcher_tags ip_allow_src_tags;
extern const matcher_tags ip_allow_dest_tags;
extern const matcher_tags socks_server_tags;

const char *parseConfigLine(char *line, matcher_line *p_line, const matcher_tags *tags);
Expand Down
42 changes: 28 additions & 14 deletions proxy/IPAllow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ enum AclOp {

const AclRecord IpAllow::ALL_METHOD_ACL(AclRecord::ALL_METHOD_MASK);

int IpAllow::configid = 0;
int IpAllow::configid = 0;
bool IpAllow::accept_check_p = true; // initializing global flag for fast deny

static ConfigUpdateHandler<IpAllow> *ipAllowUpdate;

Expand Down Expand Up @@ -108,12 +109,11 @@ IpAllow::~IpAllow()
}

void
IpAllow::Print()
IpAllow::PrintMap(IpMap *map)
{
std::ostringstream s;
s << _map.getCount() << " ACL entries";
s << '.';
for (IpMap::iterator spot(_map.begin()), limit(_map.end()); spot != limit; ++spot) {
s << map->getCount() << " ACL entries.";
for (IpMap::iterator spot(map->begin()), limit(map->end()); spot != limit; ++spot) {
char text[INET6_ADDRSTRLEN];
AclRecord const *ar = static_cast<AclRecord const *>(spot->data());

Expand Down Expand Up @@ -156,6 +156,15 @@ IpAllow::Print()
Debug("ip-allow", "%s", s.str().c_str());
}

void
IpAllow::Print()
{
Debug("ip-allow", "Printing src map");
PrintMap(&_src_map);
Debug("ip-allow", "Printing dest map");
PrintMap(&_dest_map);
}

int
IpAllow::BuildTable()
{
Expand All @@ -171,7 +180,7 @@ IpAllow::BuildTable()
bool alarmAlready = false;

// Table should be empty
ink_assert(_map.getCount() == 0);
ink_assert(_src_map.getCount() == 0 && _dest_map.getCount() == 0);

file_buf = readIntoBuffer(config_file_path, module_name, nullptr);

Expand All @@ -190,6 +199,8 @@ IpAllow::BuildTable()
}

if (*line != '\0' && *line != '#') {
const matcher_tags &ip_allow_tags =
strstr(line, ip_allow_dest_tags.match_ip) != nullptr ? ip_allow_dest_tags : ip_allow_src_tags;
errPtr = parseConfigLine(line, &line_info, &ip_allow_tags);

if (errPtr != nullptr) {
Expand All @@ -211,6 +222,7 @@ IpAllow::BuildTable()
uint32_t acl_method_mask = 0;
AclRecord::MethodSet nonstandard_methods;
bool deny_nonstandard_methods = false;
bool is_dest_ip = (strcasecmp(line_info.line[0][line_info.dest_entry], "dest_ip") == 0);
AclOp op = ACL_OP_DENY; // "shut up", I explained to the compiler.
bool op_found = false, method_found = false;
for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
Expand Down Expand Up @@ -272,10 +284,11 @@ IpAllow::BuildTable()
}

if (method_found) {
_acls.push_back(AclRecord(acl_method_mask, line_num, nonstandard_methods, deny_nonstandard_methods));
// Color with index because at this point the address
// is volatile.
_map.fill(&addr1, &addr2, reinterpret_cast<void *>(_acls.length() - 1));
Vec<AclRecord> &acls = is_dest_ip ? _dest_acls : _src_acls;
IpMap &map = is_dest_ip ? _dest_map : _src_map;
acls.push_back(AclRecord(acl_method_mask, line_num, nonstandard_methods, deny_nonstandard_methods));
// Color with index in acls because at this point the address is volatile.
map.fill(&addr1, &addr2, reinterpret_cast<void *>(acls.length() - 1));
} else {
snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : %s", module_name, config_file_path, line_num,
"Invalid action/method specified"); // changed by YTS Team, yamsat bug id -59022
Expand All @@ -288,13 +301,14 @@ IpAllow::BuildTable()
line = tokLine(nullptr, &tok_state);
}

if (_map.getCount() == 0) {
if (_src_map.getCount() == 0 && _dest_map.getCount() == 0) { // TODO: check
Warning("%s No entries in %s. All IP Addresses will be blocked", module_name, config_file_path);
} else {
// convert the coloring from indices to pointers.
for (IpMap::iterator spot(_map.begin()), limit(_map.end()); spot != limit; ++spot) {
spot->setData(&_acls[reinterpret_cast<size_t>(spot->data())]);
}
for (auto &item : _src_map)
item.setData(&_src_acls[reinterpret_cast<size_t>(item.data())]);
for (auto &item : _dest_map)
item.setData(&_dest_acls[reinterpret_cast<size_t>(item.data())]);
}

if (is_debug_tag_set("ip-allow")) {
Expand Down
50 changes: 38 additions & 12 deletions proxy/IPAllow.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,14 @@ class IpAllow : public ConfigInfo

public:
typedef IpAllow self; ///< Self reference type.
// indicator for whether we should be checking the acl record for src ip or dest ip
enum match_key_t { SRC_ADDR, DEST_ADDR };

IpAllow(const char *config_var, const char *name, const char *action_val);
~IpAllow();
void Print();
AclRecord *match(IpEndpoint const *ip) const;
AclRecord *match(sockaddr const *ip) const;
AclRecord *match(IpEndpoint const *ip, match_key_t key) const;
AclRecord *match(sockaddr const *ip, match_key_t key) const;

static void startup();
static void reconfigure();
Expand All @@ -130,35 +132,59 @@ class IpAllow : public ConfigInfo
return &ALL_METHOD_ACL;
}

/* @return The previous accept check state
* This is a global variable that is independent of
* the ip_allow configuration
*/
static bool
enableAcceptCheck(bool state)
{
bool temp = accept_check_p;
accept_check_p = state;
return temp;
}
/* @return The current accept check state
* This is a global variable that is independent of
* the ip_allow configuration
*/
static bool
isAcceptCheckEnabled()
{
return accept_check_p;
}

typedef ConfigProcessor::scoped_config<IpAllow, IpAllow> scoped_config;

private:
static int configid;
static const AclRecord ALL_METHOD_ACL;
static bool accept_check_p;

void PrintMap(IpMap *map);
int BuildTable();

char config_file_path[PATH_NAME_MAX];
const char *module_name;
const char *action;
IpMap _map;
Vec<AclRecord> _acls;
IpMap _src_map;
IpMap _dest_map;
Vec<AclRecord> _src_acls;
Vec<AclRecord> _dest_acls;
};

inline AclRecord *
IpAllow::match(IpEndpoint const *ip) const
IpAllow::match(IpEndpoint const *ip, match_key_t key) const
{
return this->match(&ip->sa);
return this->match(&ip->sa, key);
}

inline AclRecord *
IpAllow::match(sockaddr const *ip) const
IpAllow::match(sockaddr const *ip, match_key_t key) const
{
void *raw;
if (_map.contains(ip, &raw)) {
return static_cast<AclRecord *>(raw);
}
return nullptr;
void *raw = nullptr;
const IpMap &map = (key == SRC_ADDR) ? _src_map : _dest_map;
map.contains(ip, &raw);
return static_cast<AclRecord *>(raw);
}

#endif
2 changes: 1 addition & 1 deletion proxy/InkAPI.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7298,7 +7298,7 @@ const char *
TSMatcherParseSrcIPConfigLine(char *line, TSMatcherLine ml)
{
sdk_assert(sdk_sanity_check_null_ptr((void *)line) == TS_SUCCESS);
return parseConfigLine(line, (matcher_line *)ml, &ip_allow_tags);
return parseConfigLine(line, (matcher_line *)ml, &ip_allow_src_tags);
}

char *
Expand Down
46 changes: 45 additions & 1 deletion proxy/http/HttpSM.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

#include "HttpPages.h"

#include "IPAllow.h"
//#include "I_Auth.h"
//#include "HttpAuthParams.h"
#include "congest/Congestion.h"
Expand Down Expand Up @@ -4730,7 +4731,50 @@ HttpSM::do_http_server_open(bool raw)
milestones[TS_MILESTONE_SERVER_FIRST_CONNECT] = milestones[TS_MILESTONE_SERVER_CONNECT];
}

if (t_state.pCongestionEntry != nullptr) {
// Check for remap rule. If so, only apply ip_allow filter if it is activated (ip_allow_check_enabled_p set).
// Otherwise, if no remap rule is defined, apply the ip_allow filter.
if (!t_state.url_remap_success || t_state.url_map.getMapping()->ip_allow_check_enabled_p) {
// Method allowed on dest IP address check
sockaddr *server_ip = &t_state.current.server->dst_addr.sa;
IpAllow::scoped_config ip_allow;

if (ip_allow) {
const AclRecord *acl_record = ip_allow->match(server_ip, IpAllow::DEST_ADDR);
bool deny_request = false; // default is fail open.
int method = t_state.hdr_info.server_request.method_get_wksidx();

if (acl_record) {
// If empty, nothing is allowed, deny. Conversely if all methods are allowed it's OK, do not deny.
// Otherwise the method has to be checked specifically.
if (acl_record->isEmpty()) {
deny_request = true;
} else if (acl_record->_method_mask != AclRecord::ALL_METHOD_MASK) {
if (method != -1) {
deny_request = !acl_record->isMethodAllowed(method);
} else {
int method_str_len;
const char *method_str = t_state.hdr_info.server_request.method_get(&method_str_len);
deny_request = !acl_record->isNonstandardMethodAllowed(std::string(method_str, method_str_len));
}
}
}

if (deny_request) {
if (is_debug_tag_set("ip-allow")) {
ip_text_buffer ipb;
Warning("server '%s' prohibited by ip-allow policy", ats_ip_ntop(server_ip, ipb, sizeof(ipb)));
Debug("ip-allow", "Denial on %s:%s with mask %x", ats_ip_ntop(&t_state.current.server->dst_addr.sa, ipb, sizeof(ipb)),
hdrtoken_index_to_wks(method), acl_record ? acl_record->_method_mask : 0x0);
}
t_state.current.attempts = t_state.txn_conf->connect_attempts_max_retries; // prevent any more retries with this IP
call_transact_and_set_next_state(HttpTransact::Forbidden);
return;
}
}
}

// Congestion Check
if (t_state.pCongestionEntry != NULL) {
if (t_state.pCongestionEntry->F_congested() &&
(!t_state.pCongestionEntry->proxy_retry(milestones[TS_MILESTONE_SERVER_CONNECT]))) {
t_state.congestion_congested_or_failed = 1;
Expand Down
16 changes: 16 additions & 0 deletions proxy/http/HttpTransact.cc
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,16 @@ HttpTransact::BadRequest(State *s)
TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, nullptr);
}

void
HttpTransact::Forbidden(State *s)
{
DebugTxn("http_trans", "[Forbidden]"
"IpAllow marked request forbidden");
bootstrap_state_variables_from_request(s, &s->hdr_info.client_request);
build_error_response(s, HTTP_STATUS_FORBIDDEN, "Access Denied", "access#denied", NULL);
TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);
}

void
HttpTransact::HandleBlindTunnel(State *s)
{
Expand Down Expand Up @@ -6576,6 +6586,12 @@ HttpTransact::process_quick_http_filter(State *s, int method)
return;
}

// if ipallow rules are disabled by remap then don't modify anything
url_mapping *mp = s->url_map.getMapping();
if (mp && !mp->ip_allow_check_enabled_p) {
return;
}

if (s->state_machine->ua_session) {
const AclRecord *acl_record = s->state_machine->ua_session->get_acl_record();
bool deny_request = (acl_record == nullptr);
Expand Down
1 change: 1 addition & 0 deletions proxy/http/HttpTransact.h
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,7 @@ class HttpTransact
static void StartAuth(State *s);
static void HandleRequestAuthorized(State *s);
static void BadRequest(State *s);
static void Forbidden(State *s);
static void HandleFiltering(State *s);
static void DecideCacheLookup(State *s);
static void LookupSkipOpenServer(State *s);
Expand Down
Loading