• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

IPAllow.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /*****************************************************************************
00025  *
00026  *  IPAllow.cc - Implementation to IP Access Control systtem
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, ///< Allow access.
00044   ACL_OP_DENY, ///< Deny access.
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 //   Begin API functions
00055 //
00056 void
00057 IpAllow::startup()
00058 {
00059   // Should not have been initialized before
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 //   End API functions
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; // need leading vbar?
00143       uint32_t test_mask = 1; // mask for current method.
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; // need leading vbar?
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   // Table should be empty
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     // skip all blank spaces at beginning of line
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           // INKqa05845
00223           // Search for "action=ip_allow method=PURGE method=GET ..." or "action=ip_deny method=PURGE method=GET ...".
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; // "shut up", I explained to the compiler.
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             // Loop again for methods, (in case action= appears after method=)
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                 // Parse method="GET|HEAD"
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;  // in case someone does method=GET|ALL
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 { // valid method.
00266                       acl_method_mask |= AclRecord::MethodIdxToMask(method_idx);
00267                     }
00268                     method_found = true;
00269                   }
00270                 }
00271               }
00272             }
00273             // If method not specified, default to ALL
00274             if (!method_found) {
00275               method_found = true;
00276               acl_method_mask = AclRecord::ALL_METHOD_MASK;
00277               nonstandard_methods.clear();
00278             }
00279             // When deny, use bitwise complement.  (Make the rule 'allow for all
00280             // methods except those specified')
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             // Color with index because at this point the address
00290             // is volatile.
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");        //changed by YTS Team, yamsat bug id -59022
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     // convert the coloring from indices to pointers.
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 }

Generated by  doxygen 1.7.1