mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

chain.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