|
@@ -39,8 +39,15 @@ static int dirvote_publish_consensus(void);
|
|
|
static char *make_consensus_method_list(int low, int high, const char *sep);
|
|
|
|
|
|
/** The highest consensus method that we currently support. */
|
|
|
-#define MAX_SUPPORTED_CONSENSUS_METHOD 8
|
|
|
+#define MAX_SUPPORTED_CONSENSUS_METHOD 9
|
|
|
|
|
|
+/** Lowest consensus method that contains a 'directory-footer' marker */
|
|
|
+#define MIN_METHOD_FOR_FOOTER 9
|
|
|
+
|
|
|
+/** Lowest consensus method that contains bandwidth weights */
|
|
|
+#define MIN_METHOD_FOR_BW_WEIGHTS 9
|
|
|
+
|
|
|
+/** Lowest consensus method that contains consensus params */
|
|
|
#define MIN_METHOD_FOR_PARAMS 7
|
|
|
|
|
|
/** Lowest consensus method that generates microdescriptors */
|
|
@@ -71,6 +78,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
uint32_t addr;
|
|
|
routerlist_t *rl = router_get_routerlist();
|
|
|
char *version_lines = NULL;
|
|
|
+ int r;
|
|
|
networkstatus_voter_info_t *voter;
|
|
|
|
|
|
tor_assert(private_signing_key);
|
|
@@ -97,13 +105,22 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
version_lines = tor_malloc(v_len);
|
|
|
cp = version_lines;
|
|
|
if (client_versions) {
|
|
|
- tor_snprintf(cp, v_len-(cp-version_lines),
|
|
|
+ r = tor_snprintf(cp, v_len-(cp-version_lines),
|
|
|
"client-versions %s\n", client_versions);
|
|
|
+ if (r < 0) {
|
|
|
+ log_err(LD_BUG, "Insufficient memory for client-versions line");
|
|
|
+ tor_assert(0);
|
|
|
+ }
|
|
|
cp += strlen(cp);
|
|
|
}
|
|
|
- if (server_versions)
|
|
|
- tor_snprintf(cp, v_len-(cp-version_lines),
|
|
|
+ if (server_versions) {
|
|
|
+ r = tor_snprintf(cp, v_len-(cp-version_lines),
|
|
|
"server-versions %s\n", server_versions);
|
|
|
+ if (r < 0) {
|
|
|
+ log_err(LD_BUG, "Insufficient memory for server-versions line");
|
|
|
+ tor_assert(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
} else {
|
|
|
version_lines = tor_strdup("");
|
|
|
}
|
|
@@ -111,6 +128,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
len = 8192;
|
|
|
len += strlen(version_lines);
|
|
|
len += (RS_ENTRY_LEN+MICRODESC_LINE_LEN)*smartlist_len(rl->routers);
|
|
|
+ len += strlen("\ndirectory-footer\n");
|
|
|
len += v3_ns->cert->cache_info.signed_descriptor_len;
|
|
|
|
|
|
status = tor_malloc(len);
|
|
@@ -135,7 +153,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
params = tor_strdup("");
|
|
|
|
|
|
tor_assert(cert);
|
|
|
- tor_snprintf(status, len,
|
|
|
+ r = tor_snprintf(status, len,
|
|
|
"network-status-version 3\n"
|
|
|
"vote-status %s\n"
|
|
|
"consensus-methods %s\n"
|
|
@@ -159,6 +177,11 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
voter->nickname, fingerprint, voter->address,
|
|
|
ipaddr, voter->dir_port, voter->or_port, voter->contact);
|
|
|
|
|
|
+ if (r < 0) {
|
|
|
+ log_err(LD_BUG, "Insufficient memory for network status line");
|
|
|
+ tor_assert(0);
|
|
|
+ }
|
|
|
+
|
|
|
tor_free(params);
|
|
|
tor_free(flags);
|
|
|
tor_free(methods);
|
|
@@ -168,7 +191,11 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
if (!tor_digest_is_zero(voter->legacy_id_digest)) {
|
|
|
char fpbuf[HEX_DIGEST_LEN+1];
|
|
|
base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
|
|
|
- tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
|
|
|
+ r = tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
|
|
|
+ if (r < 0) {
|
|
|
+ log_err(LD_BUG, "Insufficient memory for legacy-dir-key line");
|
|
|
+ tor_assert(0);
|
|
|
+ }
|
|
|
outp += strlen(outp);
|
|
|
}
|
|
|
|
|
@@ -199,6 +226,13 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|
|
}
|
|
|
} SMARTLIST_FOREACH_END(vrs);
|
|
|
|
|
|
+ r = tor_snprintf(outp, endp-outp, "directory-footer\n");
|
|
|
+ if (r < 0) {
|
|
|
+ log_err(LD_BUG, "Insufficient memory for directory-footer line");
|
|
|
+ tor_assert(0);
|
|
|
+ }
|
|
|
+ outp += strlen(outp);
|
|
|
+
|
|
|
{
|
|
|
char signing_key_fingerprint[FINGERPRINT_LEN+1];
|
|
|
if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
|
|
@@ -648,6 +682,358 @@ dirvote_compute_params(smartlist_t *votes)
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+#define RANGE_CHECK(a,b,c,d,e,f,g,mx) \
|
|
|
+ ((a) >= 0 && (a) <= (mx) && (b) >= 0 && (b) <= (mx) && \
|
|
|
+ (c) >= 0 && (c) <= (mx) && (d) >= 0 && (d) <= (mx) && \
|
|
|
+ (e) >= 0 && (e) <= (mx) && (f) >= 0 && (f) <= (mx) && \
|
|
|
+ (g) >= 0 && (g) <= (mx))
|
|
|
+
|
|
|
+#define CHECK_EQ(a, b, margin) \
|
|
|
+ ((a)-(b) >= 0 ? (a)-(b) <= (margin) : (b)-(a) <= (margin))
|
|
|
+
|
|
|
+typedef enum {
|
|
|
+ BW_WEIGHTS_NO_ERROR = 0,
|
|
|
+ BW_WEIGHTS_RANGE_ERROR = 1,
|
|
|
+ BW_WEIGHTS_SUMG_ERROR = 2,
|
|
|
+ BW_WEIGHTS_SUME_ERROR = 3,
|
|
|
+ BW_WEIGHTS_SUMD_ERROR = 4,
|
|
|
+ BW_WEIGHTS_BALANCE_MID_ERROR = 5,
|
|
|
+ BW_WEIGHTS_BALANCE_EG_ERROR = 6
|
|
|
+} bw_weights_error_t;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Verify that any weightings satisfy the balanced formulas.
|
|
|
+ */
|
|
|
+static bw_weights_error_t
|
|
|
+networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg,
|
|
|
+ int64_t Wme, int64_t Wmd, int64_t Wee,
|
|
|
+ int64_t Wed, int64_t scale, int64_t G,
|
|
|
+ int64_t M, int64_t E, int64_t D, int64_t T,
|
|
|
+ int64_t margin, int do_balance) {
|
|
|
+ bw_weights_error_t berr = BW_WEIGHTS_NO_ERROR;
|
|
|
+
|
|
|
+ // Wed + Wmd + Wgd == 1
|
|
|
+ if (!CHECK_EQ(Wed + Wmd + Wgd, scale, margin)) {
|
|
|
+ berr = BW_WEIGHTS_SUMD_ERROR;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wmg + Wgg == 1
|
|
|
+ if (!CHECK_EQ(Wmg + Wgg, scale, margin)) {
|
|
|
+ berr = BW_WEIGHTS_SUMG_ERROR;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wme + Wee == 1
|
|
|
+ if (!CHECK_EQ(Wme + Wee, scale, margin)) {
|
|
|
+ berr = BW_WEIGHTS_SUME_ERROR;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Verify weights within range 0->1
|
|
|
+ if (!RANGE_CHECK(Wgg, Wgd, Wmg, Wme, Wmd, Wed, Wee, scale)) {
|
|
|
+ berr = BW_WEIGHTS_RANGE_ERROR;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (do_balance) {
|
|
|
+ // Wgg*G + Wgd*D == Wee*E + Wed*D, already scaled
|
|
|
+ if (!CHECK_EQ(Wgg*G + Wgd*D, Wee*E + Wed*D, (margin*T)/3)) {
|
|
|
+ berr = BW_WEIGHTS_BALANCE_EG_ERROR;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wgg*G + Wgd*D == M*scale + Wmd*D + Wme*E + Wmg*G, already scaled
|
|
|
+ if (!CHECK_EQ(Wgg*G + Wgd*D, M*scale + Wmd*D + Wme*E + Wmg*G,
|
|
|
+ (margin*T)/3)) {
|
|
|
+ berr = BW_WEIGHTS_BALANCE_MID_ERROR;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ if (berr) {
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "Bw weight mismatch %d. G="I64_FORMAT" M="I64_FORMAT
|
|
|
+ " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
|
|
|
+ berr, G, M, E, D, T);
|
|
|
+ }
|
|
|
+
|
|
|
+ return berr;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M,
|
|
|
+ int64_t E, int64_t D, int64_t T,
|
|
|
+ int64_t weight_scale)
|
|
|
+{
|
|
|
+ int64_t Wgg = -1, Wgd = -1;
|
|
|
+ int64_t Wmg = -1, Wme = -1, Wmd = -1;
|
|
|
+ int64_t Wed = -1, Wee = -1;
|
|
|
+ const char *casename;
|
|
|
+ char buf[512];
|
|
|
+ int r;
|
|
|
+
|
|
|
+ if (G <= 0 || M <= 0 || E <= 0 || D <= 0) {
|
|
|
+ log_warn(LD_DIR, "Consensus with empty bandwidth: "
|
|
|
+ "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
|
|
|
+ " D="I64_FORMAT" T="I64_FORMAT,
|
|
|
+ G, M, E, D, T);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Computed from cases in 3.4.3 of dir-spec.txt
|
|
|
+ *
|
|
|
+ * 1. Neither are scarce
|
|
|
+ * 2. Both Guard and Exit are scarce
|
|
|
+ * a. R+D <= S
|
|
|
+ * b. R+D > S
|
|
|
+ * 3. One of Guard or Exit is scarce
|
|
|
+ * a. S+D < T/3
|
|
|
+ * b. S+D >= T/3
|
|
|
+ */
|
|
|
+ if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3
|
|
|
+ bw_weights_error_t berr = 0;
|
|
|
+ /* Case 1: Neither are scarce.
|
|
|
+ *
|
|
|
+ * Attempt to ensure that we have a large amount of exit bandwidth
|
|
|
+ * in the middle position.
|
|
|
+ */
|
|
|
+ casename = "Case 1 (Wme*E = Wmd*D)";
|
|
|
+ Wgg = (weight_scale*(D+E+G+M))/(3*G);
|
|
|
+ if (D==0) Wmd = 0;
|
|
|
+ else Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
|
|
|
+ Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
|
|
|
+ Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
|
|
|
+ Wgd = 0;
|
|
|
+ Wmg = weight_scale - Wgg;
|
|
|
+ Wed = weight_scale - Wmd;
|
|
|
+
|
|
|
+ berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
|
|
|
+ weight_scale, G, M, E, D, T, 10, 1);
|
|
|
+
|
|
|
+ if (berr) {
|
|
|
+ log_warn(LD_DIR, "Bw Weights error %d for case %s. "
|
|
|
+ "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
|
|
|
+ " D="I64_FORMAT" T="I64_FORMAT,
|
|
|
+ berr, casename, G, M, E, D, T);
|
|
|
+ }
|
|
|
+ } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3
|
|
|
+ int64_t R = MIN(E, G);
|
|
|
+ int64_t S = MAX(E, G);
|
|
|
+ /*
|
|
|
+ * Case 2: Both Guards and Exits are scarce
|
|
|
+ * Balance D between E and G, depending upon
|
|
|
+ * D capacity and scarcity.
|
|
|
+ */
|
|
|
+ if (R+D < S) { // Subcase a
|
|
|
+ Wgg = weight_scale;
|
|
|
+ Wee = weight_scale;
|
|
|
+ Wmg = 0;
|
|
|
+ Wme = 0;
|
|
|
+ Wmd = 0;
|
|
|
+ if (E < G) {
|
|
|
+ casename = "Case 2a (E scarce)";
|
|
|
+ Wed = weight_scale;
|
|
|
+ Wgd = 0;
|
|
|
+ } else if (E >= G) {
|
|
|
+ casename = "Case 2a (G scarce)";
|
|
|
+ Wed = 0;
|
|
|
+ Wgd = weight_scale;
|
|
|
+ }
|
|
|
+ } else { // Subcase b: R+D > S
|
|
|
+ bw_weights_error_t berr = 0;
|
|
|
+ casename = "Case 2b (Wme*E == Wmd*D)";
|
|
|
+ if (D != 0) {
|
|
|
+ Wgg = weight_scale;
|
|
|
+ Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); // T/3 >= G (Ok)
|
|
|
+ Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); // T/3 >= M
|
|
|
+ Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
|
|
|
+ Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); // 2E+M >= T/3
|
|
|
+ Wmg = 0;
|
|
|
+ Wed = weight_scale - Wgd - Wmd;
|
|
|
+
|
|
|
+ berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
|
|
|
+ weight_scale, G, M, E, D, T, 10, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (D == 0 || berr) { // Can happen if M > T/3
|
|
|
+ casename = "Case 2b (E=G)";
|
|
|
+ Wgg = weight_scale;
|
|
|
+ Wee = weight_scale;
|
|
|
+ Wmg = 0;
|
|
|
+ Wme = 0;
|
|
|
+ Wmd = 0;
|
|
|
+ if (D == 0) Wgd = 0;
|
|
|
+ else Wgd = (weight_scale*(D+E-G))/(2*D);
|
|
|
+ Wed = weight_scale - Wgd;
|
|
|
+ berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
|
|
|
+ Wed, weight_scale, G, M, E, D, T, 10, 1);
|
|
|
+ }
|
|
|
+ if (berr != BW_WEIGHTS_NO_ERROR &&
|
|
|
+ berr != BW_WEIGHTS_BALANCE_MID_ERROR) {
|
|
|
+ log_warn(LD_DIR, "Bw Weights error %d for case %s. "
|
|
|
+ "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
|
|
|
+ " D="I64_FORMAT" T="I64_FORMAT,
|
|
|
+ berr, casename, G, M, E, D, T);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else { // if (E < T/3 || G < T/3) {
|
|
|
+ int64_t S = MIN(E, G);
|
|
|
+ // Case 3: Exactly one of Guard or Exit is scarce
|
|
|
+ if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) {
|
|
|
+ log_warn(LD_BUG,
|
|
|
+ "Bw-Weights Case 3 but with G="I64_FORMAT" M="
|
|
|
+ I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
|
|
|
+ G, M, E, D, T);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (3*(S+D) < T) { // Subcase a: S+D < T/3
|
|
|
+ if (G < E) {
|
|
|
+ casename = "Case 3a (G scarce)";
|
|
|
+ Wgg = Wgd = weight_scale;
|
|
|
+ Wmd = Wed = Wmg = 0;
|
|
|
+ // Minor subcase, if E is more scarce than M,
|
|
|
+ // keep its bandwidth in place.
|
|
|
+ if (E < M) Wme = 0;
|
|
|
+ else Wme = (weight_scale*(E-M))/(2*E);
|
|
|
+ Wee = weight_scale-Wme;
|
|
|
+ } else { // G >= E
|
|
|
+ casename = "Case 3a (E scarce)";
|
|
|
+ Wee = Wed = weight_scale;
|
|
|
+ Wmd = Wgd = Wme = 0;
|
|
|
+ // Minor subcase, if G is more scarce than M,
|
|
|
+ // keep its bandwidth in place.
|
|
|
+ if (G < M) Wmg = 0;
|
|
|
+ else Wmg = (weight_scale*(G-M))/(2*G);
|
|
|
+ Wgg = weight_scale-Wmg;
|
|
|
+ }
|
|
|
+ } else { // Subcase b: S+D >= T/3
|
|
|
+ bw_weights_error_t berr = 0;
|
|
|
+ // D != 0 because S+D >= T/3
|
|
|
+ if (G < E) {
|
|
|
+ casename = "Case 3b (G scarce, Wme*E == Wmd*D)";
|
|
|
+ Wgd = (weight_scale*(D + E - 2*G + M))/(3*D);
|
|
|
+ Wmd = (weight_scale*(D + E + G - 2*M))/(6*D);
|
|
|
+ Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
|
|
|
+ Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E);
|
|
|
+ Wgg = weight_scale;
|
|
|
+ Wmg = 0;
|
|
|
+ Wed = weight_scale - Wgd - Wmd;
|
|
|
+
|
|
|
+ berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
|
|
|
+ Wed, weight_scale, G, M, E, D, T, 10, 1);
|
|
|
+ } else { // G >= E
|
|
|
+ casename = "Case 3b (E scarce, Wme*E == Wmd*D)";
|
|
|
+ Wgg = (weight_scale*(D + E + G + M))/(3*G);
|
|
|
+ Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
|
|
|
+ Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
|
|
|
+ Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
|
|
|
+ Wgd = 0;
|
|
|
+ Wmg = weight_scale - Wgg;
|
|
|
+ Wed = weight_scale - Wmd;
|
|
|
+
|
|
|
+ berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
|
|
|
+ Wed, weight_scale, G, M, E, D, T, 10, 1);
|
|
|
+ }
|
|
|
+ if (berr) {
|
|
|
+ log_warn(LD_DIR, "Bw Weights error %d for case %s. "
|
|
|
+ "G="I64_FORMAT" M="I64_FORMAT
|
|
|
+ " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
|
|
|
+ berr, casename, G, M, E, D, T);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* We cast down the weights to 32 bit ints on the assumption that
|
|
|
+ * weight_scale is ~= 10000. We need to ensure a rogue authority
|
|
|
+ * doesn't break this assumption to rig our weights */
|
|
|
+ tor_assert(0 < weight_scale && weight_scale < INT32_MAX);
|
|
|
+
|
|
|
+ if (Wgg < 0 || Wgg > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wgg="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wgg, G, M, E, D, T);
|
|
|
+ Wgg = MAX(MIN(Wgg, weight_scale), 0);
|
|
|
+ }
|
|
|
+ if (Wgd < 0 || Wgd > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wgd="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wgd, G, M, E, D, T);
|
|
|
+ Wgd = MAX(MIN(Wgd, weight_scale), 0);
|
|
|
+ }
|
|
|
+ if (Wmg < 0 || Wmg > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wmg="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wmg, G, M, E, D, T);
|
|
|
+ Wmg = MAX(MIN(Wmg, weight_scale), 0);
|
|
|
+ }
|
|
|
+ if (Wme < 0 || Wme > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wme="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wme, G, M, E, D, T);
|
|
|
+ Wme = MAX(MIN(Wme, weight_scale), 0);
|
|
|
+ }
|
|
|
+ if (Wmd < 0 || Wmd > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wmd="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wmd, G, M, E, D, T);
|
|
|
+ Wmd = MAX(MIN(Wmd, weight_scale), 0);
|
|
|
+ }
|
|
|
+ if (Wee < 0 || Wee > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wee="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wee, G, M, E, D, T);
|
|
|
+ Wee = MAX(MIN(Wee, weight_scale), 0);
|
|
|
+ }
|
|
|
+ if (Wed < 0 || Wed > weight_scale) {
|
|
|
+ log_warn(LD_DIR, "Bw %s: Wed="I64_FORMAT"! G="I64_FORMAT
|
|
|
+ " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, Wed, G, M, E, D, T);
|
|
|
+ Wed = MAX(MIN(Wed, weight_scale), 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add consensus weight keywords
|
|
|
+ smartlist_add(chunks, tor_strdup("bandwidth-weights "));
|
|
|
+ /*
|
|
|
+ * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine
|
|
|
+ * that middle nodes need different bandwidth weights for dirport traffic,
|
|
|
+ * or that weird exit policies need special weight, or that bridges
|
|
|
+ * need special weight.
|
|
|
+ *
|
|
|
+ * NOTE: This list is sorted.
|
|
|
+ */
|
|
|
+ r = tor_snprintf(buf, sizeof(buf),
|
|
|
+ "Wbd=%d Wbe=%d Wbg=%d Wbm=%d "
|
|
|
+ "Wdb=%d "
|
|
|
+ "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d "
|
|
|
+ "Wgb=%d Wgd=%d Wgg=%d Wgm=%d "
|
|
|
+ "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n",
|
|
|
+ (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale,
|
|
|
+ (int)weight_scale,
|
|
|
+ (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee,
|
|
|
+ (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg,
|
|
|
+ (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale);
|
|
|
+ if (r<0) {
|
|
|
+ log_warn(LD_BUG,
|
|
|
+ "Not enough space in buffer for bandwidth-weights line.");
|
|
|
+ *buf = '\0';
|
|
|
+ }
|
|
|
+ smartlist_add(chunks, tor_strdup(buf));
|
|
|
+ log_notice(LD_CIRC, "Computed bandwidth weights for %s: "
|
|
|
+ "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
|
|
|
+ " T="I64_FORMAT,
|
|
|
+ casename, G, M, E, D, T);
|
|
|
+}
|
|
|
+
|
|
|
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
|
|
|
* authority <b>identity_key</b>, our private authority <b>signing_key</b>,
|
|
|
* and the number of <b>total_authorities</b> that we believe exist in our
|
|
@@ -673,9 +1059,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
char *client_versions = NULL, *server_versions = NULL;
|
|
|
smartlist_t *flags;
|
|
|
const char *flavor_name;
|
|
|
+ int64_t G=0, M=0, E=0, D=0, T=0; /* For bandwidth weights */
|
|
|
const routerstatus_format_type_t rs_format =
|
|
|
flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
|
|
|
-
|
|
|
+ char *params = NULL;
|
|
|
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
|
|
|
tor_assert(total_authorities >= smartlist_len(votes));
|
|
|
|
|
@@ -812,7 +1199,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
}
|
|
|
|
|
|
if (consensus_method >= MIN_METHOD_FOR_PARAMS) {
|
|
|
- char *params = dirvote_compute_params(votes);
|
|
|
+ params = dirvote_compute_params(votes);
|
|
|
if (params) {
|
|
|
smartlist_add(chunks, tor_strdup("params "));
|
|
|
smartlist_add(chunks, params);
|
|
@@ -1008,6 +1395,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
const char *chosen_name = NULL;
|
|
|
int exitsummary_disagreement = 0;
|
|
|
int is_named = 0, is_unnamed = 0, is_running = 0;
|
|
|
+ int is_guard = 0, is_exit = 0;
|
|
|
int naming_conflict = 0;
|
|
|
int n_listing = 0;
|
|
|
int i;
|
|
@@ -1127,7 +1515,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
} else {
|
|
|
if (flag_counts[fl_sl_idx] > n_flag_voters[fl_sl_idx]/2) {
|
|
|
smartlist_add(chosen_flags, (char*)fl);
|
|
|
- if (!strcmp(fl, "Running"))
|
|
|
+ if (!strcmp(fl, "Exit"))
|
|
|
+ is_exit = 1;
|
|
|
+ else if (!strcmp(fl, "Guard"))
|
|
|
+ is_guard = 1;
|
|
|
+ else if (!strcmp(fl, "Running"))
|
|
|
is_running = 1;
|
|
|
}
|
|
|
}
|
|
@@ -1155,6 +1547,23 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
|
|
|
}
|
|
|
|
|
|
+ if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
|
|
|
+ if (rs_out.has_bandwidth) {
|
|
|
+ T += rs_out.bandwidth;
|
|
|
+ if (is_exit && is_guard)
|
|
|
+ D += rs_out.bandwidth;
|
|
|
+ else if (is_exit)
|
|
|
+ E += rs_out.bandwidth;
|
|
|
+ else if (is_guard)
|
|
|
+ G += rs_out.bandwidth;
|
|
|
+ else
|
|
|
+ M += rs_out.bandwidth;
|
|
|
+ } else {
|
|
|
+ log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
|
|
|
+ rs_out.nickname);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* Ok, we already picked a descriptor digest we want to list
|
|
|
* previously. Now we want to use the exit policy summary from
|
|
|
* that descriptor. If everybody plays nice all the voters who
|
|
@@ -1308,6 +1717,45 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
tor_free(measured_bws);
|
|
|
}
|
|
|
|
|
|
+ if (consensus_method >= MIN_METHOD_FOR_FOOTER) {
|
|
|
+ /* Starting with consensus method 9, we clearly mark the directory
|
|
|
+ * footer region */
|
|
|
+ smartlist_add(chunks, tor_strdup("directory-footer\n"));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
|
|
|
+ int64_t weight_scale = BW_WEIGHT_SCALE;
|
|
|
+ char *bw_weight_param = NULL;
|
|
|
+
|
|
|
+ // Parse params, extract BW_WEIGHT_SCALE if present
|
|
|
+ // DO NOT use consensus_param_bw_weight_scale() in this code!
|
|
|
+ // The consensus is not formed yet!
|
|
|
+ if (strcmpstart(params, "bwweightscale=") == 0)
|
|
|
+ bw_weight_param = params;
|
|
|
+ else
|
|
|
+ bw_weight_param = strstr(params, " bwweightscale=");
|
|
|
+
|
|
|
+ if (bw_weight_param) {
|
|
|
+ int ok=0;
|
|
|
+ char *eq = strchr(bw_weight_param, '=');
|
|
|
+ if (eq) {
|
|
|
+ weight_scale = tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok,
|
|
|
+ NULL);
|
|
|
+ if (!ok) {
|
|
|
+ log_warn(LD_DIR, "Bad element '%s' in bw weight param",
|
|
|
+ escaped(bw_weight_param));
|
|
|
+ weight_scale = BW_WEIGHT_SCALE;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log_warn(LD_DIR, "Bad element '%s' in bw weight param",
|
|
|
+ escaped(bw_weight_param));
|
|
|
+ weight_scale = BW_WEIGHT_SCALE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale);
|
|
|
+ }
|
|
|
+
|
|
|
/* Add a signature. */
|
|
|
{
|
|
|
char digest[DIGEST256_LEN];
|
|
@@ -1382,11 +1830,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
networkstatus_t *c;
|
|
|
if (!(c = networkstatus_parse_vote_from_string(result, NULL,
|
|
|
NS_TYPE_CONSENSUS))) {
|
|
|
- log_err(LD_BUG,"Generated a networkstatus consensus we couldn't "
|
|
|
+ log_err(LD_BUG, "Generated a networkstatus consensus we couldn't "
|
|
|
"parse.");
|
|
|
tor_free(result);
|
|
|
return NULL;
|
|
|
}
|
|
|
+ // Verify balancing parameters
|
|
|
+ if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
|
|
|
+ networkstatus_verify_bw_weights(c);
|
|
|
+ }
|
|
|
networkstatus_vote_free(c);
|
|
|
}
|
|
|
|