Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

unigremlin.cc

Go to the documentation of this file.
00001 #include <ctime> 00002 #include <stdio.h> 00003 #include <regex.h> 00004 #include <ctype.h> 00005 #include "unigremlin.h" 00006 00007 #define MAX_DEPTH 5 00008 #define TYPE_STRING 0 00009 #define TYPE_IP 1 00010 #define TYPE_IP_NETWORK 2 00011 #define TYPE_HOSTNAME 3 00012 #define TYPE_BOOL 4 00013 #define TYPE_INT 5 00014 #define TYPE_FLOAT 6 00015 #define NUM_TYPES 7 00016 00017 VictimDict UniConfGremlin::victims(500); 00018 00019 UniConfGremlin::UniConfGremlin(WvString moniker, const UniConfKey _key, 00020 int _max_runlevel) 00021 : cfg(moniker), key(_key), max_runlevel(_max_runlevel) 00022 { 00023 runlevel = 1; 00024 num_victims = 0; 00025 if (max_runlevel > 5 || max_runlevel < 1) 00026 max_runlevel = 4; 00027 } 00028 00029 /* start(unsigned int seed) 00030 * Starts the gremlin out using the specified seed to seed the random numbers, 00031 * or if no seed is specified, uses the current time to seed them. 00032 */ 00033 void UniConfGremlin::start(unsigned int seed) 00034 { 00035 if (seed == 0) 00036 seed = time(0); 00037 00038 srand(seed); 00039 printf("Using seed %i\n", seed); 00040 find_victims(key); 00041 for (runlevel = 1; runlevel <= max_runlevel; runlevel ++) 00042 start_trouble(runlevel); 00043 runlevel = max_runlevel - 1; 00044 } 00045 00046 /* find_victims(UniConfKey _key) 00047 * Iterates through each element in the tree and adds a new victim to the list 00048 * victims with the element's key and a guess at what type of data should be 00049 * stored there. 00050 */ 00051 void UniConfGremlin::find_victims(UniConfKey _key) 00052 { 00053 UniConf::Iter i(cfg[_key]); 00054 Victim *victim; 00055 for (i.rewind(); i.next(); ) 00056 { 00057 if (i().get() == "") 00058 find_victims(i().fullkey()); 00059 else 00060 { 00061 victim = new Victim(num_victims, inspect(i().get()), i().fullkey()); 00062 victims.add(victim, true); 00063 num_victims ++; 00064 } 00065 } 00066 } 00067 00068 /* inspect(WvString element) 00069 * Inspects the string element in an attempt to guess what type of data should 00070 * be stored there. Returns an integer representing what type the gremlin 00071 * thinks it is. 00072 */ 00073 int UniConfGremlin::inspect(WvString element) 00074 { 00075 char *elem = element.edit(); 00076 // rough expression for an ip network 00077 char *ipNetExp = "[0-9].*\\.[0-9].*\\.[0-9].*\\.[0-9].*"; 00078 if (is_bool(elem)) 00079 return TYPE_BOOL; 00080 00081 if (isdigit(elem[0])) 00082 { 00083 regex_t preg1; 00084 regmatch_t pmatch1[1]; 00085 regcomp(&preg1, ipNetExp, REG_EXTENDED | REG_NOSUB); 00086 00087 if (!regexec(&preg1, elem, 1, pmatch1, 0)) 00088 { 00089 if (elem[element.len() - 2] == '/' || 00090 elem[element.len() - 3] == '/') 00091 return TYPE_IP_NETWORK; 00092 else 00093 return TYPE_IP; 00094 } 00095 } 00096 // now we just brute force the rest of the string 00097 for (size_t i = 1; i < element.len(); i++) 00098 { 00099 if (!isdigit(elem[i])) 00100 // either string or hostname, return string for now 00101 return TYPE_STRING; 00102 } 00103 // either int or float, return int for now 00104 return TYPE_INT; 00105 } 00106 00107 /* is_bool(char *elem) 00108 * Returns true if the string stored in elem represents a boolean valuation 00109 */ 00110 bool UniConfGremlin::is_bool(char *elem) 00111 { 00112 const char *strs[] = { 00113 "true", "yes", "on", "enabled", "1", 00114 "false", "no", "off", "disabled", "0" 00115 }; 00116 00117 for (size_t i = 0; i < sizeof(strs) / sizeof(const char*); ++i) 00118 if (strcasecmp(elem, strs[i]) == 0) 00119 return true; 00120 00121 return false; 00122 } 00123 00124 /* change_value(bool use_valid_data) 00125 * Changes a random value from the list of victims, the victim list includes 00126 * previously deleted victims as well, so this could potentially add previously 00127 * deleted values back in as well. Changes it with new random data. 00128 */ 00129 void UniConfGremlin::change_value(bool use_valid_data) 00130 { 00131 int r = num_victims + 1; 00132 while (r >= num_victims) 00133 { 00134 r = (int)(((double)rand() / (double)RAND_MAX) * (num_victims)); 00135 } 00136 last_change = WvString("Changed %s to be the value", victims[r]->name); 00137 WvString new_value; 00138 if (use_valid_data) 00139 { 00140 if (victims[r]->type == TYPE_INT) 00141 { 00142 int new_value = rand(); 00143 cfg[victims[r]->name].setint(new_value); 00144 last_change = WvString("%s %s\n", last_change, new_value); 00145 } 00146 else 00147 { 00148 WvString new_value = rand_str(victims[r]->type); 00149 cfg[victims[r]->name].set(new_value); 00150 last_change = WvString("%s %s\n", last_change, new_value); 00151 } 00152 } 00153 else 00154 { 00155 int s = (int)(((double)rand() / (double)RAND_MAX) * 2); 00156 if (s) 00157 { 00158 int new_value = rand(); 00159 cfg[victims[r]->name].setint(rand()); 00160 last_change = WvString("%s %s\n", last_change, new_value); 00161 } 00162 else 00163 { 00164 WvString new_value = rand_str(victims[r]->type); 00165 int t = (int)(((double)rand() / (double)RAND_MAX) * NUM_TYPES); 00166 cfg[victims[r]->name].set(rand_str(t)); 00167 last_change = WvString("%s %s\n", last_change, new_value); 00168 } 00169 00170 } 00171 cfg[victims[r]->name].commit(); 00172 00173 } 00174 00175 /* add_value() 00176 * Adds a random value into the UniConf also randomly selecting the type and 00177 * contents. 00178 */ 00179 void UniConfGremlin::add_value() 00180 { 00181 int depth = (int)(((double)rand() / (double)RAND_MAX) * MAX_DEPTH); 00182 WvString key_name = "", elem; 00183 00184 // generate a key name 32 characters or less 00185 for (int i = 0; i < depth; i++) 00186 { 00187 elem = ""; 00188 int length = (int)(((double)rand() / (double)RAND_MAX) * 8); 00189 for (int j = 0; j < length; j++) 00190 { 00191 // generate a valid written character (lower case right now) 00192 int num = (int)((((double)rand() / (double)RAND_MAX) * 25) 00193 + 97); 00194 char c[2]; 00195 c[0] = (char)num; 00196 c[1] = '\0'; 00197 elem = WvString("%s%s", elem, c); 00198 } 00199 if (i > 0) 00200 key_name = WvString("%s/%s", key_name, elem); 00201 else 00202 key_name = elem; 00203 } 00204 key_name = WvString("%s/%s", key, key_name); 00205 00206 last_change = WvString("Added the key %s with the new value", key_name); 00207 // generate a value 00208 int num = (int)((double)rand() / (double)RAND_MAX); 00209 Victim *victim; 00210 if (num) 00211 // generate number 00212 { 00213 int new_value = rand(); 00214 cfg[key_name].setint(new_value); 00215 victim = new Victim(num_victims, TYPE_INT, key_name); 00216 last_change = WvString("%s %s\n", last_change, new_value); 00217 } 00218 else 00219 // generate string 00220 { 00221 int type = (int)(((double)rand() / (double)RAND_MAX) * 5 00222 + TYPE_STRING); 00223 WvString new_value = rand_str(type); 00224 cfg[key_name].set(new_value); 00225 victim = new Victim(num_victims, TYPE_STRING, key_name); 00226 last_change = WvString("%s %s\n", last_change, new_value); 00227 } 00228 victims.add(victim, true); 00229 num_victims ++; 00230 cfg[key_name].commit(); 00231 } 00232 00233 /* start_trouble(int curr_runlevel) 00234 * This is where it makes the calls for 1000 actions on the specified runlevel 00235 * and calls the appropriate method. 00236 */ 00237 void UniConfGremlin::start_trouble(int curr_runlevel) 00238 { 00239 printf("%s\n", UniConfGremlin::curr_runlevel().cstr()); 00240 int r = curr_runlevel; 00241 for (int i = 0; i < 1000; i ++) 00242 { 00243 if (curr_runlevel == 5) 00244 r = (int)(((double)rand() / (double)RAND_MAX) * 4) + 1; 00245 00246 if (r == 1) 00247 change_value(true); 00248 else if (r == 2) 00249 change_value(false); 00250 else if (r == 3) 00251 add_value(); 00252 else if (r >= 4) 00253 // randomly delete value, but always remember as a victim for fun 00254 { 00255 int r = (int)(((double)rand() / (double)RAND_MAX) * (num_victims)); 00256 cfg[victims[r]->name].remove(); 00257 cfg[victims[r]->name].commit(); 00258 last_change = WvString("Deleted the key %s\n", victims[r]->name); 00259 } 00260 } 00261 } 00262 00263 /* rand_str(int type) 00264 * Returns a random string of the specified format(by type) 00265 * - not great random numbers, had to increase the range to 1 above the max 00266 * range I wanted, just since when casting back to int it chops off the 00267 * fractional part, and there is very low probability of getting 00268 * rand() = RAND_MAX but it will happen from time to time. 00269 */ 00270 WvString UniConfGremlin::rand_str(int type) 00271 { 00272 if (type == TYPE_STRING || type == TYPE_HOSTNAME) 00273 { 00274 int a = (int)(((double)rand() / (double)RAND_MAX) * 200); 00275 WvString result = ""; 00276 for (int i = 0; i < a; i++) 00277 { 00278 int b = (int)((((double)rand() / (double)RAND_MAX) * 26) + 97); 00279 char c[2]; 00280 c[0] = (char)b; 00281 c[1] = '\0'; 00282 result = WvString("%s%s", result, c); 00283 } 00284 return WvString("%s", result); 00285 } 00286 else if (type == TYPE_BOOL) 00287 { 00288 const char *strs[] = { 00289 "true", "yes", "on", "enabled", "1", 00290 "false", "no", "off", "disabled", "0" 00291 }; 00292 int a = (int)(((double)rand() / (double)RAND_MAX) * 10); 00293 return WvString("%s", strs[a]); 00294 } 00295 else if (type == TYPE_IP || type == TYPE_IP_NETWORK) 00296 { 00297 int a = (int)(((double)rand() / (double)RAND_MAX) * 256), 00298 b = (int)(((double)rand() / (double)RAND_MAX) * 256), 00299 c = (int)(((double)rand() / (double)RAND_MAX) * 256), 00300 d = (int)(((double)rand() / (double)RAND_MAX) * 256); 00301 if (type == TYPE_IP_NETWORK) 00302 { 00303 int e = (int)(((double)rand() / (double)RAND_MAX) * 33); 00304 return WvString("%s.%s.%s.%s/%s", a, b, c, d, e); 00305 } 00306 else 00307 return WvString("%s.%s.%s.%s", a, b, c, d); 00308 } 00309 else if (type == TYPE_INT) 00310 return rand(); 00311 else if (type == TYPE_FLOAT) 00312 return rand(); 00313 else 00314 return ""; 00315 } 00316 00317 /* type_name(int type) 00318 * Returns a string representation of the type passed to it. 00319 */ 00320 WvString UniConfGremlin::type_name(int type) 00321 { 00322 if (type == TYPE_STRING) 00323 return "String"; 00324 else if (type == TYPE_IP) 00325 return "IP"; 00326 else if (type == TYPE_IP_NETWORK) 00327 return "IP Network"; 00328 else if (type == TYPE_HOSTNAME) 00329 return "Hostname"; 00330 else if (type == TYPE_BOOL) 00331 return "Boolean"; 00332 else if (type == TYPE_INT) 00333 return "Integer"; 00334 else if (type == TYPE_FLOAT) 00335 return "Float"; 00336 else 00337 return "Unknown"; 00338 } 00339 00340 /* curr_runlevel() 00341 * Returns a string describing the current runlevel. 00342 */ 00343 WvString UniConfGremlin::curr_runlevel() 00344 { 00345 if (runlevel == 1) 00346 return "1 - Change keys with valid data."; 00347 else if (runlevel == 2) 00348 return "2 - Change keys with invalid data."; 00349 else if (runlevel == 3) 00350 return "3 - Add new keys."; 00351 else if (runlevel == 4) 00352 return "4 - Remove keys."; 00353 else if (runlevel == 5) 00354 return "5 - Add/Remove keys, change keys with valid/invalid data."; 00355 else 00356 return WvString("Apparently I'm on runlevel %s", runlevel); 00357 } 00358 00359 /* status() 00360 * Displays the most recent runlevel and action. 00361 */ 00362 WvString UniConfGremlin::status() 00363 { 00364 return WvString("Last Runlevel was : %s\nLast Action was : %s", 00365 curr_runlevel(), last_change); 00366 } 00367 00368 /* test() 00369 * Code can be put here to test and tweak the functionality of the gremlin 00370 */ 00371 void UniConfGremlin::test() 00372 { 00373 printf("Testing Random Generators\n"); 00374 printf("STRING %s\n", UniConfGremlin::rand_str(TYPE_STRING).cstr()); 00375 printf("IP %s\n", UniConfGremlin::rand_str(TYPE_IP).cstr()); 00376 printf("IP_NETWORK %s\n", UniConfGremlin::rand_str(TYPE_IP_NETWORK).cstr()); 00377 printf("HOSTNAME %s\n", UniConfGremlin::rand_str(TYPE_HOSTNAME).cstr()); 00378 printf("BOOL %s\n", UniConfGremlin::rand_str(TYPE_BOOL).cstr()); 00379 printf("INT %s\n", UniConfGremlin::rand_str(TYPE_INT).cstr()); 00380 printf("FLOAT %s\n", UniConfGremlin::rand_str(TYPE_FLOAT).cstr()); 00381 printf("Testing adding things to the UniConf\n"); 00382 int count = 0; 00383 for (int i = 0; i < 5; i ++) 00384 { 00385 printf("Adding 5 random strings of type %s\n", type_name(i).cstr()); 00386 for (int j = 0; j < 5; j ++) 00387 { 00388 WvString rand = rand_str(i); 00389 printf("Adding %s\n", rand.cstr()); 00390 cfg[count].set(rand); 00391 cfg[count].commit(); 00392 count ++; 00393 } 00394 } 00395 printf("Adding 5 random ints\n"); 00396 for (int i = 5; i < 10; i ++) 00397 { 00398 int randint = rand(); 00399 printf("Adding %i\n", randint); 00400 cfg[count].setint(randint); 00401 cfg[count].commit(); 00402 count ++; 00403 } 00404 printf("Testing Find Victims\n"); 00405 find_victims(key); 00406 for (int i = 0; i < num_victims; i ++) 00407 { 00408 printf("%s:", victims[i]->name.cstr()); 00409 printf("%s:", type_name(victims[i]->type).cstr()); 00410 printf("%s\n", cfg[victims[i]->name].get().cstr()); 00411 } 00412 00413 printf("Testing Start Trouble\n"); 00414 start_trouble(1); 00415 }

Generated on Tue Oct 5 01:09:19 2004 for WvStreams by doxygen 1.3.7