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 }