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 "ink_platform.h"
00032 #include "ink_defs.h"
00033 #include "ink_time.h"
00034 
00035 #include "Main.h"
00036 #include "URL.h"
00037 #include "Tokenizer.h"
00038 #include "ControlBase.h"
00039 #include "MatcherUtils.h"
00040 #include "HTTP.h"
00041 #include "ControlMatcher.h"
00042 #include "HdrUtils.h"
00043 #include "Vec.h"
00044 
00045 #include <ts/TsBuffer.h>
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 # define TS_IP_OCTETS(x) \
00055   reinterpret_cast<unsigned char const*>(&(x))[0],   \
00056     reinterpret_cast<unsigned char const*>(&(x))[1], \
00057     reinterpret_cast<unsigned char const*>(&(x))[2], \
00058     reinterpret_cast<unsigned char const*>(&(x))[3]
00059 
00060 
00061 ControlBase::Modifier::~Modifier() {}
00062 ControlBase::Modifier::Type ControlBase::Modifier::type() const { return MOD_INVALID; }
00063 
00064 namespace {
00065 
00066 struct TimeMod : public ControlBase::Modifier {
00067   time_t start_time;
00068   time_t end_time;
00069 
00070   static char const * const NAME;
00071 
00072   virtual Type type() const;
00073   virtual char const * name() const;
00074   virtual bool check(HttpRequestData* req) const;
00075   virtual void print(FILE* f) const;
00076   static TimeMod* make(char * value, char const ** error);
00077   static const char* timeOfDayToSeconds(const char *time_str, time_t * seconds);
00078 };
00079 
00080 char const * const TimeMod::NAME = "Time";
00081 ControlBase::Modifier::Type TimeMod::type() const { return MOD_TIME; }
00082 char const * TimeMod::name() const { return NAME; }
00083 
00084 void TimeMod::print(FILE* f) const {
00085   fprintf(f, "%s=%ld-%ld  ",
00086     
00087     
00088     this->name(), static_cast<long>(start_time), static_cast<long>(end_time)
00089   );
00090 }
00091 bool TimeMod::check(HttpRequestData* req) const {
00092   struct tm cur_time;
00093   time_t timeOfDay = req->xact_start;
00094   
00095   ink_localtime_r(&timeOfDay, &cur_time);
00096   timeOfDay = cur_time.tm_hour*(60 * 60) + cur_time.tm_min*60 + cur_time.tm_sec;
00097   return start_time <= timeOfDay && timeOfDay <= end_time;
00098 }
00099 
00100 TimeMod*
00101 TimeMod::make(char * value, char const ** error) {
00102   Tokenizer rangeTok("-");
00103   TimeMod* mod = 0;
00104   TimeMod tmp;
00105   int num_tok;
00106 
00107   num_tok = rangeTok.Initialize(value, SHARE_TOKS);
00108   if (num_tok == 1) {
00109     *error = "End time not specified";
00110   } else if (num_tok > 2) {
00111     *error = "Malformed time range";
00112   } else if (
00113     0 == (*error = timeOfDayToSeconds(rangeTok[0], &tmp.start_time))
00114     && 0 == (*error = timeOfDayToSeconds(rangeTok[1], &tmp.end_time))
00115   ) {
00116     mod = new TimeMod(tmp);
00117   }
00118   return mod;
00119 }
00120 
00121 
00122 
00123 
00124 
00125 
00126 const char *
00127 TimeMod::timeOfDayToSeconds(const char *time_str, time_t * seconds) {
00128   int hour = 0;
00129   int min = 0;
00130   int sec = 0;
00131   time_t tmp = 0;
00132 
00133   
00134   if (sscanf(time_str, "%d:%d:%d", &hour, &min, &sec) != 3) {
00135     
00136     if (sscanf(time_str, "%d:%d", &hour, &min) != 2) {
00137       return "Malformed time specified";
00138     }
00139   }
00140 
00141   if (!(hour >= 0 && hour <= 23)) return "Illegal hour specification";
00142 
00143   tmp = hour * 60;
00144 
00145   if (!(min >= 0 && min <= 59)) return "Illegal minute specification";
00146 
00147   tmp = (tmp + min) * 60;
00148 
00149   if (!(sec >= 0 && sec <= 59)) return "Illegal second specification";
00150 
00151   tmp += sec;
00152 
00153   *seconds = tmp;
00154   return 0;
00155 }
00156 
00157 
00158 struct PortMod : public ControlBase::Modifier {
00159   int start_port;
00160   int end_port;
00161 
00162   static char const * const NAME;
00163 
00164   virtual char const * name() const;
00165   virtual bool check(HttpRequestData* req) const;
00166   virtual void print(FILE* f) const;
00167 
00168   static PortMod* make(char* value, char const **error);
00169 };
00170 
00171 char const * const PortMod::NAME = "Port";
00172 char const * PortMod::name() const { return NAME; }
00173 
00174 void PortMod::print(FILE* f) const {
00175   fprintf(f, "%s=%d-%d  ", this->name(), start_port, end_port);
00176 }
00177 
00178 bool PortMod::check(HttpRequestData* req) const {
00179   int port = req->hdr->port_get();
00180   return start_port <= port && port <= end_port;
00181 }
00182 
00183 PortMod*
00184 PortMod::make(char* value, char const ** error) {
00185   Tokenizer rangeTok("-");
00186   PortMod tmp;
00187   int num_tok = rangeTok.Initialize(value, SHARE_TOKS);
00188 
00189   *error = 0;
00190   if (num_tok > 2) {
00191     *error = "Malformed Range";
00192     
00193   } else if (sscanf(rangeTok[0], "%d", &tmp.start_port) != 1) {
00194     *error = "Invalid start port";
00195   } else if (num_tok == 2) {
00196     
00197     if (sscanf(rangeTok[1], "%d", &tmp.end_port) != 1)
00198       *error = "Invalid end port";
00199     else if (tmp.end_port < tmp.start_port)
00200       *error = "Malformed Range: end port < start port";
00201   } else {
00202     tmp.end_port = tmp.start_port;
00203   }
00204 
00205   
00206   
00207   return *error ? 0 : new PortMod(tmp);
00208 }
00209 
00210 
00211 struct IPortMod : public ControlBase::Modifier {
00212   int _port;
00213 
00214   static char const * const NAME;
00215 
00216   IPortMod(int port);
00217 
00218   virtual char const * name() const;
00219   virtual bool check(HttpRequestData* req) const;
00220   virtual void print(FILE* f) const;
00221   static IPortMod* make(char* value, char const ** error);
00222 };
00223 
00224 char const * const IPortMod::NAME = "IPort";
00225 IPortMod::IPortMod(int port) : _port(port) {}
00226 char const * IPortMod::name() const { return NAME; }
00227 
00228 void IPortMod::print(FILE* f) const {
00229   fprintf(f, "%s=%d  ", this->name(), _port);
00230 }
00231 bool IPortMod::check(HttpRequestData* req) const {
00232   return req->incoming_port == _port;
00233 }
00234 
00235 IPortMod*
00236 IPortMod::make(char* value, char const ** error) {
00237   IPortMod* zret = 0;
00238   int port;
00239   
00240   if (sscanf(value, "%u", &port) == 1) {
00241     zret = new IPortMod(port);
00242   } else {
00243     *error = "Invalid incoming port";
00244   }
00245   return zret;
00246 }
00247 
00248 struct SrcIPMod : public ControlBase::Modifier {
00249   
00250   IpEndpoint start_addr; 
00251   IpEndpoint end_addr; 
00252 
00253   static char const * const NAME;
00254 
00255   virtual Type type() const;
00256   virtual char const * name() const;
00257   virtual bool check(HttpRequestData* req) const;
00258   virtual void print(FILE* f) const;
00259   static SrcIPMod* make(char * value, char const ** error);
00260 };
00261 
00262 char const * const SrcIPMod::NAME = "SrcIP";
00263 ControlBase::Modifier::Type SrcIPMod::type() const { return MOD_SRC_IP; }
00264 char const * SrcIPMod::name() const { return NAME; }
00265 
00266 void SrcIPMod::print(FILE* f) const {
00267   ip_text_buffer b1, b2;
00268   fprintf(f, "%s=%s-%s  "
00269     ,this->name()
00270     , ats_ip_ntop(&start_addr.sa, b1, sizeof(b1))
00271     , ats_ip_ntop(&end_addr.sa, b2, sizeof(b2))
00272   );
00273 }
00274 bool SrcIPMod::check(HttpRequestData* req) const {
00275   
00276   return ats_ip_addr_cmp(&start_addr, &req->src_ip) <= 0
00277     && ats_ip_addr_cmp(&req->src_ip, &end_addr) <= 0
00278     ;
00279 }
00280 SrcIPMod*
00281 SrcIPMod::make(char * value, char const ** error ) {
00282   SrcIPMod tmp;
00283   SrcIPMod* zret = 0;
00284   *error = ExtractIpRange(value, &tmp.start_addr.sa, &tmp.end_addr.sa);
00285 
00286   if (!*error) zret = new SrcIPMod(tmp);
00287   return zret;
00288 }
00289 
00290 struct SchemeMod : public ControlBase::Modifier {
00291   int _scheme; 
00292 
00293   static char const * const NAME;
00294 
00295   SchemeMod(int scheme);
00296 
00297   virtual Type type() const;
00298   virtual char const * name() const;
00299   virtual bool check(HttpRequestData* req) const;
00300   virtual void print(FILE* f) const;
00301 
00302   char const* getWksText() const;
00303 
00304   static SchemeMod* make(char * value, char const ** error);
00305 };
00306 
00307 char const * const SchemeMod::NAME = "Scheme";
00308 
00309 SchemeMod::SchemeMod(int scheme) : _scheme(scheme) {}
00310 
00311 ControlBase::Modifier::Type SchemeMod::type() const { return MOD_SCHEME; }
00312 char const * SchemeMod::name() const { return NAME; }
00313 char const *
00314 SchemeMod::getWksText() const {
00315   return hdrtoken_index_to_wks(_scheme);
00316 }
00317 
00318 bool SchemeMod::check(HttpRequestData* req) const {
00319   return req->hdr->url_get()->scheme_get_wksidx() == _scheme;
00320 }
00321 void SchemeMod::print(FILE* f) const {
00322   fprintf(f, "%s=%s  ", this->name(), hdrtoken_index_to_wks(_scheme));
00323 }
00324 SchemeMod*
00325 SchemeMod::make(char * value, char const ** error) {
00326   SchemeMod* zret = 0;
00327   int scheme = hdrtoken_tokenize(value, strlen(value));
00328   if (scheme < 0) {
00329     *error = "Unknown scheme";
00330   } else {
00331     zret = new SchemeMod(scheme);
00332   }
00333   return zret;
00334 }
00335 
00336 
00337 
00338 
00339 struct TextMod : public ControlBase::Modifier {
00340   ts::Buffer text;
00341 
00342   TextMod();
00343   ~TextMod();
00344 
00345   
00346   virtual void print(FILE* f) const;
00347 
00348   
00349   void set(const char * value);
00350 
00351 };
00352 
00353 TextMod::TextMod() : text() {}
00354 TextMod::~TextMod() {
00355   free(text.data());
00356 }
00357 
00358 void TextMod::print(FILE* f) const {
00359   fprintf(f, "%s=%*s  ", this->name(), static_cast<int>(text.size()), text.data());
00360 }
00361 
00362 void TextMod::set(const char * value) {
00363   free(this->text.data());
00364   this->text.set(ats_strdup(value), strlen(value));
00365 }
00366 
00367 struct MultiTextMod : public ControlBase::Modifier {
00368   Vec<ts::Buffer> text_vec;
00369   MultiTextMod();
00370   ~MultiTextMod();
00371 
00372   
00373   void set(char * value);
00374 
00375   
00376   virtual void print(FILE* f) const;
00377 };
00378 
00379 MultiTextMod::MultiTextMod() {}
00380 MultiTextMod::~MultiTextMod() {
00381   text_vec.clear();
00382 }
00383 
00384 void MultiTextMod::print(FILE* f) const {
00385   for_Vec(ts::Buffer, text_iter, this->text_vec)
00386     fprintf(f, "%s=%*s ", this->name(),static_cast<int>(text_iter.size()),text_iter.data());
00387 }
00388 
00389 void MultiTextMod::set(char * value) {
00390   Tokenizer rangeTok(",");
00391   int num_tok = rangeTok.Initialize(value, SHARE_TOKS);
00392   for(int i = 0; i < num_tok; i++){
00393     ts::Buffer text;
00394     text.set(ats_strdup(rangeTok[i]), strlen(rangeTok[i]));
00395     this->text_vec.push_back(text);
00396   }
00397 }
00398 
00399 
00400 struct MethodMod : public TextMod {
00401   static char const * const NAME;
00402 
00403   virtual Type type() const;
00404   virtual char const * name() const;
00405   virtual bool check(HttpRequestData* req) const;
00406 
00407   static MethodMod* make(char * value, char const ** error);
00408 };
00409 char const * const MethodMod::NAME = "Method";
00410 ControlBase::Modifier::Type MethodMod::type() const { return MOD_METHOD; }
00411 char const * MethodMod::name() const { return NAME; }
00412 bool MethodMod::check(HttpRequestData* req) const {
00413   int method_len;
00414   char const* method = req->hdr->method_get(&method_len);
00415   return method_len >= static_cast<int>(text.size())
00416     && 0 == strncasecmp(method, text.data(), text.size())
00417     ;
00418 }
00419 MethodMod*
00420 MethodMod::make(char * value, char const **) {
00421   MethodMod* mod = new MethodMod();
00422   mod->set(value);
00423   return mod;
00424 }
00425 
00426 
00427 struct PrefixMod : public TextMod {
00428   static char const * const NAME;
00429 
00430   virtual Type type() const;
00431   virtual char const * name() const;
00432   virtual bool check(HttpRequestData* req) const;
00433   static PrefixMod* make(char * value, char const ** error);
00434 };
00435 
00436 char const * const PrefixMod::NAME = "Prefix";
00437 ControlBase::Modifier::Type PrefixMod::type() const { return MOD_PREFIX; }
00438 char const * PrefixMod::name() const { return NAME; }
00439 bool PrefixMod::check(HttpRequestData* req) const {
00440   int path_len;
00441   char const* path = req->hdr->url_get()->path_get(&path_len);
00442   bool zret = path_len >= static_cast<int>(text.size())
00443     && 0 == memcmp(path, text.data(), text.size())
00444     ;
00445 
00446 
00447 
00448 
00449 
00450 
00451   return zret;
00452 }
00453 PrefixMod*
00454 PrefixMod::make(char * value, char const ** ) {
00455   PrefixMod* mod = new PrefixMod();
00456   
00457   
00458   while ('/' == *value) ++value;
00459   mod->set(value);
00460   return mod;
00461 }
00462 
00463 
00464 struct SuffixMod : public MultiTextMod {
00465   static char const * const NAME;
00466 
00467   virtual Type type() const;
00468   virtual char const * name() const;
00469   virtual bool check(HttpRequestData* req) const;
00470   static SuffixMod* make(char * value, char const ** error);
00471 };
00472 char const * const SuffixMod::NAME = "Suffix";
00473 ControlBase::Modifier::Type SuffixMod::type() const { return MOD_SUFFIX; }
00474 char const * SuffixMod::name() const { return NAME; }
00475 bool SuffixMod::check(HttpRequestData* req) const {
00476   int path_len;
00477   char const* path = req->hdr->url_get()->path_get(&path_len);
00478   if(1 == static_cast<int>(this->text_vec.count()) && 1 == static_cast<int>(this->text_vec[0].size()) && 0 == strcmp(this->text_vec[0].data(),"*"))
00479     return true;
00480   for_Vec(ts::Buffer, text_iter, this->text_vec){
00481     if (path_len >= static_cast<int>(text_iter.size()) && 0 == strncasecmp(path + path_len - text_iter.size(), text_iter.data(), text_iter.size()))
00482       return true;
00483   }
00484   return false;
00485 }
00486 SuffixMod*
00487 SuffixMod::make(char * value, char const ** ) {
00488   SuffixMod* mod = new SuffixMod();
00489   mod->set(value);
00490   return mod;
00491 }
00492 
00493 
00494 struct TagMod : public TextMod {
00495   static char const * const NAME;
00496 
00497   virtual Type type() const;
00498   virtual char const * name() const;
00499   virtual bool check(HttpRequestData* req) const;
00500   static TagMod* make(char * value, char const ** error);
00501 };
00502 char const * const TagMod::NAME = "Tag";
00503 ControlBase::Modifier::Type TagMod::type() const { return MOD_TAG; }
00504 char const * TagMod::name() const { return NAME; }
00505 bool TagMod::check(HttpRequestData* req) const {
00506   return 0 == strcmp(req->tag, text.data());
00507 }
00508 TagMod*
00509 TagMod::make(char * value, char const ** ) {
00510   TagMod* mod = new TagMod();
00511   mod->set(value);
00512   return mod;
00513 }
00514 
00515 
00516 } 
00517 
00518 ControlBase::~ControlBase() {
00519   this->clear();
00520 }
00521 
00522 void
00523 ControlBase::clear() {
00524   _mods.delete_and_clear();
00525 }
00526 
00527 
00528 
00529 void
00530 ControlBase::Print() {
00531   int n = _mods.length();
00532 
00533   if (0 >= n) return;
00534 
00535   printf("\t\t\t");
00536   for (intptr_t i = 0; i < n; ++i) {
00537     Modifier* cur_mod = _mods[i];
00538     if (!cur_mod) printf("INVALID  ");
00539     else cur_mod->print(stdout);
00540   }
00541   printf("\n");
00542 }
00543 
00544 char const *
00545 ControlBase::getSchemeModText() const {
00546   char const* zret = 0;
00547   Modifier* mod = this->findModOfType(Modifier::MOD_SCHEME);
00548   if (mod) zret = static_cast<SchemeMod*>(mod)->getWksText();
00549   return zret;
00550 }
00551 
00552 bool
00553 ControlBase::CheckModifiers(HttpRequestData * request_data) {
00554   if (!request_data->hdr) {
00555     
00556     
00557     return true;
00558   }
00559 
00560   
00561   
00562   if (!request_data->tag && findModOfType(Modifier::MOD_TAG))
00563     return false;
00564 
00565   forv_Vec(Modifier, cur_mod, _mods)
00566     if (cur_mod && ! cur_mod->check(request_data)) return false;
00567 
00568   return true;
00569 }
00570 
00571 enum mod_errors {
00572   ME_UNKNOWN,
00573   ME_PARSE_FAILED,
00574   ME_BAD_MOD,
00575   ME_CALLEE_GENERATED
00576 };
00577 
00578 static const char *errorFormats[] = {
00579   "Unknown error parsing modifier",
00580   "Unable to parse modifier",
00581   "Unknown modifier",
00582   "Callee Generated",
00583 };
00584 
00585 ControlBase::Modifier*
00586 ControlBase::findModOfType(Modifier::Type t) const {
00587   forv_Vec(Modifier, m, _mods)
00588     if (m && t == m->type()) return m;
00589   return 0;
00590 }
00591 
00592 const char *
00593 ControlBase::ProcessModifiers(matcher_line * line_info) {
00594   
00595   const char *errBuf = NULL;
00596   mod_errors err = ME_UNKNOWN;
00597 
00598   int n_elts = line_info->num_el; 
00599 
00600   
00601   if (0 >= n_elts) return 0;
00602   
00603   _mods.clear();
00604   _mods.reserve(n_elts);
00605 
00606   
00607   
00608   
00609   
00610   for (int i = 0; n_elts && ME_UNKNOWN == err && i < MATCHER_MAX_TOKENS; ++i) {
00611     Modifier* mod = 0;
00612 
00613     char * label = line_info->line[0][i];
00614     char * value = line_info->line[1][i];
00615 
00616     if (!label) continue; 
00617     if (!value) {
00618       err = ME_PARSE_FAILED;
00619       break;
00620     }
00621 
00622     if (strcasecmp(label, "port") == 0) {
00623       mod = PortMod::make(value, &errBuf);
00624     } else if (strcasecmp(label, "iport") == 0) {
00625       mod = IPortMod::make(value, &errBuf);
00626     } else if (strcasecmp(label, "scheme") == 0) {
00627       mod = SchemeMod::make(value, &errBuf);
00628     } else if (strcasecmp(label, "method") == 0) {
00629       mod = MethodMod::make(value, &errBuf);
00630     } else if (strcasecmp(label, "prefix") == 0) {
00631       mod = PrefixMod::make(value, &errBuf);
00632     } else if (strcasecmp(label, "suffix") == 0) {
00633       mod = SuffixMod::make(value, &errBuf);
00634     } else if (strcasecmp(label, "src_ip") == 0) {
00635       mod = SrcIPMod::make(value, &errBuf);
00636     } else if (strcasecmp(label, "time") == 0) {
00637       mod = TimeMod::make(value, &errBuf);
00638     } else if (strcasecmp(label, "tag") == 0) {
00639       mod = TagMod::make(value, &errBuf);
00640     } else {
00641       err = ME_BAD_MOD;
00642     }
00643 
00644     if (errBuf) err = ME_CALLEE_GENERATED; 
00645 
00646     
00647     if (ME_UNKNOWN == err) {
00648       _mods.push_back(mod);
00649       --n_elts;
00650     } else {
00651       delete mod; 
00652     }
00653   }
00654 
00655   if (err != ME_UNKNOWN) {
00656     this->clear();
00657     if (err != ME_CALLEE_GENERATED) {
00658       errBuf = errorFormats[err];
00659     }
00660   }
00661 
00662   return errBuf;
00663 }