tchain.c - mixmaster - mixmaster 3.0 patched for libressl HTML git clone git://parazyd.org/mixmaster.git DIR Log DIR Files DIR Refs DIR README --- tchain.c (11809B) --- 1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. 2 3 Mixmaster may be redistributed and modified under certain conditions. 4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 5 ANY KIND, either express or implied. See the file COPYRIGHT for 6 details. 7 8 Prepare messages for remailer chain 9 $Id: chain.c 934 2006-06-24 13:40:39Z rabbi $ */ 10 11 12 #include "mix3.h" 13 #include <string.h> 14 #include <ctype.h> 15 #include <assert.h> 16 #include <stdlib.h> 17 18 void clienterr(BUFFER *msgbuf, char *err) 19 { 20 if (msgbuf) { 21 buf_sets(msgbuf, "Error: "); 22 buf_appends(msgbuf, err); 23 } else 24 errlog(ERRORMSG, "%s\n", err); 25 } 26 27 void parse_badchains(int badchains[MAXREM][MAXREM], char *file, char *startindicator, REMAILER *remailer, int maxrem) { 28 int i,j; 29 FILE *list; 30 char line[LINELEN]; 31 32 if (!badchains) 33 return; 34 35 for (i = 0; i < maxrem; i++ ) 36 for (j = 0; j < maxrem; j++ ) 37 badchains[i][j] = 0; 38 list = mix_openfile(TYPE2REL, "r"); 39 if (list != NULL) { 40 while (fgets(line, sizeof(line), list) != NULL && 41 !strleft(line, startindicator)) ; 42 while (fgets(line, sizeof(line), list) != NULL && 43 strleft(line, "(")) { 44 char *left, *right, *tmp; 45 int lefti, righti; 46 47 left = line + 1; 48 while (*left == ' ') 49 left ++; 50 51 tmp = left + 1; 52 while (*tmp != ' ' && *tmp != '\0' && *tmp != ')') 53 tmp ++; 54 if (*tmp == '\0' || *tmp == ')') 55 /* parsing this line failed */ 56 continue; 57 *tmp = '\0'; 58 59 right = tmp+1; 60 while (*right == ' ') 61 right ++; 62 tmp = right + 1; 63 while (*tmp != ' ' && *tmp != '\0' && *tmp != ')') 64 tmp ++; 65 if (*tmp == '\0') 66 /* parsing this line failed */ 67 continue; 68 *tmp = '\0'; 69 70 lefti = -1; 71 righti = -1; 72 for (i = 1; i < maxrem; i++) { 73 if (strcmp(remailer[i].name, left) == 0) 74 lefti = i; 75 if (strcmp(remailer[i].name, right) == 0) 76 righti = i; 77 } 78 if (strcmp(left, "*") == 0) 79 lefti = 0; 80 if (strcmp(right, "*") == 0) 81 righti = 0; 82 83 if (lefti == -1 || righti == -1) 84 /* we don't know about one or both remailers */ 85 continue; 86 badchains[lefti][righti] = 1; 87 } 88 fclose(list); 89 /* If some broken chain includes all remailers (*) mark it broken for 90 * every single remailer - this simplifies handling in other places */ 91 for (i=1; i < maxrem; i++ ) { 92 if (badchains[0][i]) 93 for (j=1; j < maxrem; j++ ) 94 badchains[j][i] = 1; 95 if (badchains[i][0]) 96 for (j=1; j < maxrem; j++ ) 97 badchains[i][j] = 1; 98 } 99 } 100 } 101 102 103 int chain_select(int hop[], char *chainstr, int maxrem, REMAILER *remailer, 104 int type, BUFFER *feedback) 105 { 106 int len = 0; 107 int i, j, k; 108 BUFFER *chain, *selected, *addr; 109 chain = buf_new(); 110 selected = buf_new(); 111 addr = buf_new(); 112 113 if (chainstr == NULL || chainstr[0] == '\0') 114 buf_sets(chain, CHAIN); 115 else 116 buf_sets(chain, chainstr); 117 118 /* put the chain backwards: final hop is in hop[0] */ 119 120 for (i = chain->length; i >= 0; i--) 121 if (i == 0 || chain->data[i - 1] == ',' 122 || chain->data[i - 1] == ';' || chain->data[i - 1] == ':') { 123 for (j = i; isspace(chain->data[j]);) /* ignore whitespace */ 124 j++; 125 if (chain->data[j] == '\0') 126 break; 127 128 if (chain->data[j] == '*') 129 k = 0; 130 #if 0 131 else if (isdigit(chain->data[j])) 132 k = atoi(chain->data + j); 133 #endif /* 0 */ 134 else { 135 buf_sets(selected, chain->data + j); 136 rfc822_addr(selected, addr); 137 buf_clear(selected); 138 buf_getline(addr, selected); 139 if (!selected->length) 140 buf_sets(selected, chain->data + j); 141 142 for (k = 0; k < maxrem; k++) 143 if (((remailer[k].flags.mix && type == 0) || 144 (remailer[k].flags.cpunk && type == 1) || 145 (remailer[k].flags.newnym && type == 2)) && 146 (streq(remailer[k].name, selected->data) || 147 strieq(remailer[k].addr, selected->data) || 148 (selected->data[0] == '@' && strifind(remailer[k].addr, 149 selected->data)))) 150 break; 151 } 152 if (k < 0 || k >= maxrem) { 153 if (feedback != NULL) { 154 buf_appendf(feedback, "No such remailer: %b", selected); 155 buf_nl(feedback); 156 } 157 #if 0 158 k = 0; 159 #else /* end of 0 */ 160 len = -1; 161 goto end; 162 #endif /* else not 0 */ 163 } 164 hop[len++] = k; 165 if (len >= 20) { /* array passed in is has length 20 */ 166 if (feedback != NULL) { 167 buf_appends(feedback, "Chain too long.\n"); 168 } 169 break; 170 } 171 if (i > 0) 172 chain->data[i - 1] = '\0'; 173 } 174 end: 175 buf_free(chain); 176 buf_free(selected); 177 buf_free(addr); 178 return len; 179 } 180 181 int chain_randfinal(int type, REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem, int rtype, int chain[], int chainlen, int ignore_constraints_if_necessary) 182 { 183 int randavail; 184 int i; 185 int t; 186 int select[MAXREM]; 187 int secondtolasthop = (chainlen <= 1 ? -1 : chain[1]); 188 int constraints_ignored = 0; 189 190 t = rtype; 191 if (rtype == 2) 192 t = 1; 193 194 start: 195 randavail = 0; 196 /* select a random final hop */ 197 for (i = 1; i < maxrem; i++) { 198 select[i] = 199 ((remailer[i].flags.mix && rtype == 0) || /* remailer supports type */ 200 (remailer[i].flags.pgp && remailer[i].flags.ek && rtype == 1) || 201 (remailer[i].flags.newnym && rtype == 2)) && 202 (remailer[i].info[t].reliability >= 100 * RELFINAL || constraints_ignored ) && /* remailer has sufficient reliability */ 203 (remailer[i].info[t].latency <= MAXLAT || constraints_ignored ) && /* remailer has low enough latency */ 204 (remailer[i].info[t].latency >= MINLAT || constraints_ignored ) && /* remailer has high enough latency */ 205 (type == MSG_NULL || !remailer[i].flags.middle) && /* remailer is not middleman */ 206 !remailer[i].flags.star_ex && /* remailer is not excluded from random selection */ 207 (remailer[i].flags.post || type != MSG_POST) && /* remailer supports post when this is a post */ 208 ((secondtolasthop == -1) || !badchains[secondtolasthop][i]); 209 /* we only have hop or the previous one can send to this (may be random) */ 210 randavail += select[i]; 211 } 212 213 for (i = 1; i <= DISTANCE; i++) 214 if (i < chainlen && select[chain[i]] && chain[i]) { 215 select[chain[i]] = 0; 216 randavail--; 217 } 218 219 assert(randavail >= 0); 220 if (randavail == 0) { 221 if (ignore_constraints_if_necessary && !constraints_ignored) { 222 errlog(WARNING, "No reliable remailers. Ignoring for randhop\n"); 223 constraints_ignored = 1; 224 goto start; 225 }; 226 i = -1; 227 } else { 228 do 229 i = rnd_number(maxrem - 1) + 1; 230 while (!select[i]); 231 } 232 return (i); 233 } 234 235 int chain_rand(REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem, 236 int thischain[], int chainlen, int t, int ignore_constraints_if_necessary) 237 /* set random chain. returns 0 if not random, 1 if random, -1 on error */ 238 /* t... 0 for mixmaster Type II 239 * 1 for cypherpunk Type I 240 */ 241 { 242 int hop; 243 int err = 0; 244 int constraints_ignored = 0; 245 246 assert(t == 0 || t == 1); 247 248 start: 249 for (hop = 0; hop < chainlen; hop++) 250 if (thischain[hop] == 0) { 251 int select[MAXREM]; 252 int randavail = 0; 253 int i; 254 255 err = 1; 256 if (hop > 0) 257 assert(thischain[hop-1]); /* we already should have chosen a remailer after this one */ 258 for (i = 1; i < maxrem; i++) { 259 select[i] = ((remailer[i].flags.mix && t == 0) || /* remailer supports type */ 260 (remailer[i].flags.pgp && remailer[i].flags.ek && t == 1)) && 261 (remailer[i].info[t].reliability >= 100 * MINREL || constraints_ignored ) && /* remailer has sufficient reliability */ 262 (remailer[i].info[t].latency <= MAXLAT || constraints_ignored ) && /* remailer has low enough latency */ 263 (remailer[i].info[t].latency >= MINLAT || constraints_ignored ) && /* remailer has high enough latency */ 264 !remailer[i].flags.star_ex && /* remailer is not excluded from random selection */ 265 !badchains[i][0] && !badchains[i][thischain[hop-1]] && /* remailer can send to the next one */ 266 (hop == chainlen-1 || !badchains[thischain[hop+1]][i]); 267 /* we are at the first hop or the previous one can send to this (may be random) */ 268 randavail += select[i]; 269 } 270 271 for (i = hop - DISTANCE; i <= hop + DISTANCE; i++) 272 if (i >= 0 && i < chainlen && select[thischain[i]] && thischain[i]) { 273 select[thischain[i]] = 0; 274 randavail--; 275 } 276 277 278 assert(randavail >= 0); 279 if (randavail < 1) { 280 if (ignore_constraints_if_necessary && !constraints_ignored) { 281 errlog(WARNING, "No reliable remailers. Ignoring for randhop\n"); 282 constraints_ignored = 1; 283 goto start; 284 }; 285 err = -1; 286 goto end; 287 } 288 do 289 thischain[hop] = rnd_number(maxrem - 1) + 1; 290 while (!select[thischain[hop]]); 291 } 292 end: 293 return (err); 294 } 295 296 int mix_encrypt(int type, BUFFER *message, char *chainstr, int numcopies, 297 BUFFER *chainlist) 298 { 299 return (mix2_encrypt(type, message, chainstr, numcopies, 0, chainlist)); 300 } 301 302 /* float chain_reliablity(char *chain, int chaintype, 303 char *reliability_string); 304 * 305 * Compute reliablity of a chain. 306 * 307 * We get the reliablity of the chain by multiplying the reliablity of 308 * every remailer in the chain. The return value is the reliablity of 309 * the chain, or a negative number if the reliablity can not be 310 * calculated. There are two reasons why may not be able to calculated 311 * the reliablity: A remailer in the chain is selected randomly, or we 312 * don't have statistics about one of the remailers in the chain. 313 * remailer_type indicates the remailer type: 314 * 0 = Mixmaster, 1 = Cypherpunk 315 * 316 * If reliability_string is non-NULL, the reliability is also returned 317 * as a string in this variable. The size of the string must be at 318 * least 9 characters! 319 * 320 * This function has been added by Gerd Beuster. (gb@uni-koblenz.de) 321 *--------------------------------------------------------------------*/ 322 323 float chain_reliability(char *chain, int chaintype, 324 char *reliability_string){ 325 326 float acc_reliability = 1; /* Accumulated reliablity */ 327 char *name_start, *name_end; /* temporary pointers used 328 in string scanning */ 329 char remailer_name[20]; /* The length of the array is taken from mix3.h. */ 330 int error = 0; 331 int maxrem; 332 int i; 333 int previous = -1; 334 REMAILER remailer[MAXREM]; 335 int badchains[MAXREM][MAXREM]; 336 337 /* chaintype 0=mix 1=ek 2=newnym */ 338 assert((chaintype == 0) || (chaintype == 1)); 339 maxrem = (chaintype == 0 ? mix2_rlist(remailer, badchains) : t1_rlist(remailer, badchains)); 340 341 /* Dissect chain */ 342 name_start = chain; 343 name_end = chain; 344 while(*name_end != '\0'){ /* While string not scanned completely */ 345 do /* Get next remailer */ 346 name_end+=sizeof(char); 347 while( (*name_end != ',') && (*name_end != '\0')); 348 strncpy(remailer_name, name_start, 349 (name_end - name_start) / sizeof(char) + 1*sizeof(char)); 350 remailer_name[name_end-name_start]='\0'; 351 /* Lookup reliablity for remailer remailer_name */ 352 for(i=0; 353 (i < maxrem) && (strcmp(remailer[i].name, remailer_name) != 0); 354 i++); 355 if(!strcmp(remailer[i].name, remailer_name)) { /* Found it! */ 356 acc_reliability *= 357 ((float) remailer[i].info[chaintype].reliability) / 10000; 358 if (previous != -1) { 359 if (badchains[previous][i] || badchains[0][i]) 360 acc_reliability = 0; 361 } 362 previous = i; 363 } else 364 error = 1; /* Did not find this remailer. We can't calculate 365 the reliablity for the whole chain. */ 366 name_start = name_end+sizeof(char); 367 } 368 369 if(error || (name_start==name_end)) 370 acc_reliability = -1; 371 372 /* Convert reliability into string, if appropriate */ 373 if(reliability_string){ 374 if(acc_reliability < 0) 375 sprintf(reliability_string, " n/a "); 376 else{ 377 sprintf(reliability_string, "%6.2f", acc_reliability*100); 378 *(reliability_string+6*sizeof(char)) = '%'; 379 } 380 } 381 382 return acc_reliability; 383 } 384