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
00030
00031
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
00047
00048
00049
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
00069
00070
00071
00072
00073 int UniConfGremlin::inspect(WvString element)
00074 {
00075 char *elem = element.edit();
00076
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
00097 for (size_t i = 1; i < element.len(); i++)
00098 {
00099 if (!isdigit(elem[i]))
00100
00101 return TYPE_STRING;
00102 }
00103
00104 return TYPE_INT;
00105 }
00106
00107
00108
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
00125
00126
00127
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
00176
00177
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
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
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
00208 int num = (int)((double)rand() / (double)RAND_MAX);
00209 Victim *victim;
00210 if (num)
00211
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
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
00234
00235
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
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
00264
00265
00266
00267
00268
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
00318
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
00341
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
00360
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
00369
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 }