00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "libts.h"
00032 #include "Main.h"
00033 #include "IPAllow.h"
00034 #include "ProxyConfig.h"
00035 #include "StatSystem.h"
00036 #include "P_EventSystem.h"
00037 #include "P_Cache.h"
00038 #include "hdrs/HdrToken.h"
00039
00040 #include <sstream>
00041
00042 enum AclOp {
00043 ACL_OP_ALLOW,
00044 ACL_OP_DENY,
00045 };
00046
00047 const AclRecord IpAllow::ALL_METHOD_ACL(AclRecord::ALL_METHOD_MASK);
00048
00049 int IpAllow::configid = 0;
00050
00051 static ConfigUpdateHandler<IpAllow> * ipAllowUpdate;
00052
00053
00054
00055
00056 void
00057 IpAllow::startup()
00058 {
00059
00060 ink_assert(IpAllow::configid == 0);
00061
00062 ipAllowUpdate = new ConfigUpdateHandler<IpAllow>();
00063 ipAllowUpdate->attach("proxy.config.cache.ip_allow.filename");
00064
00065 reconfigure();
00066 }
00067
00068 void
00069 IpAllow::reconfigure()
00070 {
00071 self *new_table;
00072
00073 Note("ip_allow.config updated, reloading");
00074
00075 new_table = new self("proxy.config.cache.ip_allow.filename", "IpAllow", "ip_allow");
00076 new_table->BuildTable();
00077
00078 configid = configProcessor.set(configid, new_table);
00079 }
00080
00081 IpAllow *
00082 IpAllow::acquire()
00083 {
00084 return (IpAllow *)configProcessor.get(configid);
00085 }
00086
00087 void
00088 IpAllow::release(IpAllow * lookup)
00089 {
00090 configProcessor.release(configid, lookup);
00091 }
00092
00093
00094
00095
00096
00097
00098 IpAllow::IpAllow(
00099 const char *config_var,
00100 const char *name,
00101 const char *action_val
00102 ) : module_name(name),
00103 action(action_val)
00104 {
00105 ats_scoped_str config_path(RecConfigReadConfigPath(config_var));
00106
00107 config_file_path[0] = '\0';
00108 ink_release_assert(config_path);
00109
00110 ink_strlcpy(config_file_path, config_path, sizeof(config_file_path));
00111 }
00112
00113 IpAllow::~IpAllow()
00114 {
00115 }
00116
00117 void
00118 IpAllow::Print() {
00119 std::ostringstream s;
00120 s << _map.getCount() << " ACL entries";
00121 s << '.';
00122 for ( IpMap::iterator spot(_map.begin()), limit(_map.end())
00123 ; spot != limit
00124 ; ++spot
00125 ) {
00126 char text[INET6_ADDRSTRLEN];
00127 AclRecord const* ar = static_cast<AclRecord const*>(spot->data());
00128
00129 s << std::endl << " Line " << ar->_src_line << ": "
00130 << ats_ip_ntop(spot->min(), text, sizeof text)
00131 ;
00132 if (0 != ats_ip_addr_cmp(spot->min(), spot->max())) {
00133 s << " - " << ats_ip_ntop(spot->max(), text, sizeof text);
00134 }
00135 s << " method=";
00136 uint32_t mask = AclRecord::ALL_METHOD_MASK & ar->_method_mask;
00137 if (AclRecord::ALL_METHOD_MASK == mask) {
00138 s << "ALL";
00139 } else if (0 == mask) {
00140 s << "NONE";
00141 } else {
00142 bool leader = false;
00143 uint32_t test_mask = 1;
00144 for ( int i = 0 ; i < HTTP_WKSIDX_METHODS_CNT ; ++i, test_mask<<=1 ) {
00145 if (mask & test_mask) {
00146 if (leader)
00147 s << '|';
00148 s << hdrtoken_index_to_wks(i + HTTP_WKSIDX_CONNECT);
00149 leader = true;
00150 }
00151 }
00152 }
00153 if (!ar->_nonstandard_methods.empty()) {
00154 s << " nonstandard method=";
00155 bool leader = false;
00156 for (AclRecord::MethodSet::iterator iter = ar->_nonstandard_methods.begin(),
00157 end = ar->_nonstandard_methods.end(); iter != end; ++iter) {
00158 if (leader) {
00159 s << '|';
00160 }
00161 s << *iter;
00162 leader = true;
00163 }
00164 }
00165 }
00166 Debug("ip-allow", "%s", s.str().c_str());
00167 }
00168
00169 int
00170 IpAllow::BuildTable()
00171 {
00172 char *tok_state = NULL;
00173 char *line = NULL;
00174 const char *errPtr = NULL;
00175 char errBuf[1024];
00176 char *file_buf = NULL;
00177 int line_num = 0;
00178 IpEndpoint addr1;
00179 IpEndpoint addr2;
00180 matcher_line line_info;
00181 bool alarmAlready = false;
00182
00183
00184 ink_assert(_map.getCount() == 0);
00185
00186 file_buf = readIntoBuffer(config_file_path, module_name, NULL);
00187
00188 if (file_buf == NULL) {
00189 Warning("%s Failed to read %s. All IP Addresses will be blocked", module_name, config_file_path);
00190 return 1;
00191 }
00192
00193 line = tokLine(file_buf, &tok_state);
00194 while (line != NULL) {
00195
00196 ++line_num;
00197
00198
00199 while (*line && isspace(*line)) {
00200 line++;
00201 }
00202
00203 if (*line != '\0' && *line != '#') {
00204
00205 errPtr = parseConfigLine(line, &line_info, &ip_allow_tags);
00206
00207 if (errPtr != NULL) {
00208 snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : %s",
00209 module_name, config_file_path, line_num, errPtr);
00210 SignalError(errBuf, alarmAlready);
00211 } else {
00212
00213 ink_assert(line_info.type == MATCH_IP);
00214
00215 errPtr = ExtractIpRange(line_info.line[1][line_info.dest_entry], &addr1.sa, &addr2.sa);
00216
00217 if (errPtr != NULL) {
00218 snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : %s",
00219 module_name, config_file_path, line_num, errPtr);
00220 SignalError(errBuf, alarmAlready);
00221 } else {
00222
00223
00224 char *label, *val;
00225 uint32_t acl_method_mask = 0;
00226 AclRecord::MethodSet nonstandard_methods;
00227 bool deny_nonstandard_methods = false;
00228 AclOp op = ACL_OP_DENY;
00229 bool op_found = false, method_found = false;
00230 for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
00231 label = line_info.line[0][i];
00232 val = line_info.line[1][i];
00233 if (label == NULL) {
00234 continue;
00235 }
00236 if (strcasecmp(label, "action") == 0) {
00237 if (strcasecmp(val, "ip_allow") == 0) {
00238 op_found = true, op = ACL_OP_ALLOW;
00239 } else if (strcasecmp(val, "ip_deny") == 0) {
00240 op_found = true, op = ACL_OP_DENY;
00241 }
00242 }
00243 }
00244 if (op_found) {
00245
00246 for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
00247 label = line_info.line[0][i];
00248 val = line_info.line[1][i];
00249 if (label == NULL) {
00250 continue;
00251 }
00252 if (strcasecmp(label, "method") == 0) {
00253 char *method_name, *sep_ptr = 0;
00254
00255 for (method_name = strtok_r(val, "|", &sep_ptr); method_name != NULL; method_name = strtok_r(NULL, "|", &sep_ptr)) {
00256 if (strcasecmp(method_name, "ALL") == 0) {
00257 method_found = false;
00258 break;
00259 } else {
00260 int method_name_len = strlen(method_name);
00261 int method_idx = hdrtoken_tokenize(method_name, method_name_len);
00262 if (method_idx < HTTP_WKSIDX_CONNECT || method_idx >= HTTP_WKSIDX_CONNECT + HTTP_WKSIDX_METHODS_CNT) {
00263 nonstandard_methods.insert(method_name);
00264 Debug("ip-allow", "Found nonstandard method [%s] on line %d", method_name, line_num);
00265 } else {
00266 acl_method_mask |= AclRecord::MethodIdxToMask(method_idx);
00267 }
00268 method_found = true;
00269 }
00270 }
00271 }
00272 }
00273
00274 if (!method_found) {
00275 method_found = true;
00276 acl_method_mask = AclRecord::ALL_METHOD_MASK;
00277 nonstandard_methods.clear();
00278 }
00279
00280
00281 if (op == ACL_OP_DENY) {
00282 acl_method_mask = AclRecord::ALL_METHOD_MASK & ~acl_method_mask;
00283 deny_nonstandard_methods = true;
00284 }
00285 }
00286
00287 if (method_found) {
00288 _acls.push_back(AclRecord(acl_method_mask, line_num, nonstandard_methods, deny_nonstandard_methods));
00289
00290
00291 _map.fill(
00292 &addr1, &addr2,
00293 reinterpret_cast<void*>(_acls.length()-1)
00294 );
00295 } else {
00296 snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : %s", module_name, config_file_path, line_num, "Invalid action/method specified");
00297 SignalError(errBuf, alarmAlready);
00298 }
00299 }
00300 }
00301 }
00302
00303 line = tokLine(NULL, &tok_state);
00304 }
00305
00306 if (_map.getCount() == 0) {
00307 Warning("%s No entries in %s. All IP Addresses will be blocked", module_name, config_file_path);
00308 } else {
00309
00310 for ( IpMap::iterator spot(_map.begin()), limit(_map.end())
00311 ; spot != limit
00312 ; ++spot
00313 ) {
00314 spot->setData(&_acls[reinterpret_cast<size_t>(spot->data())]);
00315 }
00316 }
00317
00318 if (is_debug_tag_set("ip-allow")) {
00319 Print();
00320 }
00321
00322 ats_free(file_buf);
00323 return 0;
00324 }