/** Set *<b>out</b> to a newly allocated SOCKS4a resolve request with * <b>username</b> and <b>hostname</b> as provided. Return the number * of bytes in the request. */ static ssize_t build_socks_resolve_request(char **out, const char *username, const char *hostname, int reverse, int version) { size_t len = 0; tor_assert(out); tor_assert(username); tor_assert(hostname); if (version == 4) { len = 8 + strlen(username) + 1 + strlen(hostname) + 1; *out = tor_malloc(len); (*out)[0] = 4; /* SOCKS version 4 */ (*out)[1] = '\xF0'; /* Command: resolve. */ set_uint16((*out)+2, htons(0)); /* port: 0. */ set_uint32((*out)+4, htonl(0x00000001u)); /* addr: 0.0.0.1 */ memcpy((*out)+8, username, strlen(username)+1); memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1); } else if (version == 5) { int is_ip_address; tor_addr_t addr; size_t addrlen; int ipv6; is_ip_address = tor_addr_parse(&addr, hostname) != -1; if (!is_ip_address && reverse) { log_err(LD_GENERAL, "Tried to do a reverse lookup on a non-IP!"); return -1; } ipv6 = reverse && tor_addr_family(&addr) == AF_INET6; addrlen = reverse ? (ipv6 ? 16 : 4) : 1 + strlen(hostname); len = 6 + addrlen; *out = tor_malloc(len); (*out)[0] = 5; /* SOCKS version 5 */ (*out)[1] = reverse ? '\xF1' : '\xF0'; /* RESOLVE_PTR or RESOLVE */ (*out)[2] = 0; /* reserved. */ if (reverse) { (*out)[3] = ipv6 ? 4 : 1; if (ipv6) memcpy((*out)+4, tor_addr_to_in6_addr8(&addr), 16); else set_uint32((*out)+4, tor_addr_to_ipv4n(&addr)); } else { (*out)[3] = 3; (*out)[4] = (char)(uint8_t)(addrlen - 1); memcpy((*out)+5, hostname, addrlen - 1); } set_uint16((*out)+4+addrlen, 0); /* port */ } else { tor_assert(0); } return len; }
/** Set *<b>out</b> to a newly allocated SOCKS4a resolve request with * <b>username</b> and <b>hostname</b> as provided. Return the number * of bytes in the request. */ static int build_socks_connect_request(char **out, const char *username, const char *hostname, int reverse, int version) { size_t len = 0; assert(out); assert(username); assert(hostname); if (version == 4) { len = 8 + strlen(username) + 1 + strlen(hostname) + 1; *out = malloc(len); (*out)[0] = 4; /* SOCKS version 4 */ (*out)[1] = '\x01'; /* Command: connect. */ set_uint16((*out)+2, htons(80)); /* port: 80. */ set_uint32((*out)+4, htonl(0x00000001u)); /* addr: 0.0.0.1 */ memcpy((*out)+8, username, strlen(username)+1); memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1); } else if (version == 5) { int is_ip_address; struct in_addr in; size_t addrlen; is_ip_address = inet_aton(hostname, &in); if (!is_ip_address && reverse) { fprintf(stderr,"Tried to do a reverse lookup on a non-IP!\n"); return -1; } addrlen = is_ip_address ? 4 : 1 + strlen(hostname); len = 6 + addrlen; *out = malloc(len); (*out)[0] = 5; /* SOCKS version 5 */ (*out)[1] = '\x01'; /* connect. */ (*out)[2] = 0; /* reserved. */ (*out)[3] = is_ip_address ? 1 : 3; if (is_ip_address) { set_uint32((*out)+4, in.s_addr); } else { (*out)[4] = (char)(uint8_t)(addrlen - 1); memcpy((*out)+5, hostname, addrlen - 1); } set_uint16((*out)+4+addrlen, htons(80)); /* port */ } else { assert(0); } return len; }
/** Set *<b>out</b> to a newly allocated SOCKS4a resolve request with * <b>username</b> and <b>hostname</b> as provided. Return the number * of bytes in the request. */ static int build_socks_resolve_request(char **out, const char *username, const char *hostname, int reverse, int version) { size_t len = 0; tor_assert(out); tor_assert(username); tor_assert(hostname); if (version == 4) { len = 8 + strlen(username) + 1 + strlen(hostname) + 1; *out = tor_malloc(len); (*out)[0] = 4; /* SOCKS version 4 */ (*out)[1] = '\xF0'; /* Command: resolve. */ set_uint16((*out)+2, htons(0)); /* port: 0. */ set_uint32((*out)+4, htonl(0x00000001u)); /* addr: 0.0.0.1 */ memcpy((*out)+8, username, strlen(username)+1); memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1); } else if (version == 5) { int is_ip_address; struct in_addr in; size_t addrlen; is_ip_address = tor_inet_aton(hostname, &in); if (!is_ip_address && reverse) { log_err(LD_GENERAL, "Tried to do a reverse lookup on a non-IP!"); return -1; } addrlen = reverse ? 4 : 1 + strlen(hostname); len = 6 + addrlen; *out = tor_malloc(len); (*out)[0] = 5; /* SOCKS version 5 */ (*out)[1] = reverse ? '\xF1' : '\xF0'; /* RESOLVE_PTR or RESOLVE */ (*out)[2] = 0; /* reserved. */ (*out)[3] = reverse ? 1 : 3; if (reverse) { set_uint32((*out)+4, in.s_addr); } else { (*out)[4] = (char)(uint8_t)(addrlen - 1); memcpy((*out)+5, hostname, addrlen - 1); } set_uint16((*out)+4+addrlen, 0); /* port */ } else { tor_assert(0); } return len; }
static void write_metadata_for_file (GString *out, MetaFile *file, GList **stringvs, GHashTable *strings, GHashTable *key_hash) { GList *l; MetaData *data; guint32 key; g_assert (file->metadata_pointer != 0); set_uint32 (out, file->metadata_pointer, out->len); append_uint32 (out, g_list_length (file->data), NULL); for (l = file->data; l != NULL; l = l->next) { data = l->data; key = GPOINTER_TO_UINT (g_hash_table_lookup (key_hash, data->key)); if (data->is_list) key |= KEY_IS_LIST_MASK; append_uint32 (out, key, NULL); if (data->is_list) append_stringv (out, data->values, stringvs); else append_string (out, data->value, strings); } }
static void stringv_block_end (GString *out, GHashTable *string_block, GList *stringv_block) { guint32 table_offset; StringvInfo *info; GList *l, *s; for (l = stringv_block; l != NULL; l = l->next) { info = l->data; table_offset = out->len; append_uint32 (out, g_list_length (info->strings), NULL); for (s = info->strings; s != NULL; s = s->next) append_string (out, s->data, string_block); set_uint32 (out, info->offset, table_offset); g_free (info); } g_list_free (stringv_block); /* Pad to 32bit */ while (out->len % 4 != 0) g_string_append_c (out, 0); }
static void string_block_end (GString *out, GHashTable *string_block) { char *string; GList *offsets, *l; guint32 string_offset, offset; GHashTableIter iter; g_hash_table_iter_init (&iter, string_block); while (g_hash_table_iter_next (&iter, (gpointer *)&string, (gpointer *)&offsets)) { string_offset = out->len; g_string_append_len (out, string, strlen (string) + 1); for (l = offsets; l != NULL; l = l->next) { offset = GPOINTER_TO_UINT (l->data); set_uint32 (out, offset, string_offset); } } g_hash_table_destroy (string_block); /* Pad to 32bit */ while (out->len % 4 != 0) g_string_append_c (out, 0); }
static void test_util_format_unaligned_accessors(void *ignored) { (void)ignored; char buf[9] = "onionsoup"; // 6f6e696f6e736f7570 tt_u64_op(get_uint64(buf+1), OP_EQ, htonll(U64_LITERAL(0x6e696f6e736f7570))); tt_uint_op(get_uint32(buf+1), OP_EQ, htonl(0x6e696f6e)); tt_uint_op(get_uint16(buf+1), OP_EQ, htons(0x6e69)); tt_uint_op(get_uint8(buf+1), OP_EQ, 0x6e); set_uint8(buf+7, 0x61); tt_mem_op(buf, OP_EQ, "onionsoap", 9); set_uint16(buf+6, htons(0x746f)); tt_mem_op(buf, OP_EQ, "onionstop", 9); set_uint32(buf+1, htonl(0x78696465)); tt_mem_op(buf, OP_EQ, "oxidestop", 9); set_uint64(buf+1, htonll(U64_LITERAL(0x6266757363617465))); tt_mem_op(buf, OP_EQ, "obfuscate", 9); done: ; }
int do_rtpg(int fd, void* resp, long resplen, unsigned int timeout) { struct rtpg_command cmd; struct sg_io_hdr hdr; unsigned char sense[SENSE_BUFF_LEN]; memset(&cmd, 0, sizeof(cmd)); cmd.op = OPERATION_CODE_RTPG; rtpg_command_set_service_action(&cmd); set_uint32(cmd.length, resplen); PRINT_HEX((unsigned char *) &cmd, sizeof(cmd)); memset(&hdr, 0, sizeof(hdr)); hdr.interface_id = 'S'; hdr.cmdp = (unsigned char *) &cmd; hdr.cmd_len = sizeof(cmd); hdr.dxfer_direction = SG_DXFER_FROM_DEV; hdr.dxferp = resp; hdr.dxfer_len = resplen; hdr.mx_sb_len = sizeof(sense); hdr.sbp = sense; hdr.timeout = get_prio_timeout(timeout, SGIO_TIMEOUT); if (ioctl(fd, SG_IO, &hdr) < 0) return -RTPG_RTPG_FAILED; if (scsi_error(&hdr)) { PRINT_DEBUG("do_rtpg: SCSI error!\n"); return -RTPG_RTPG_FAILED; } PRINT_HEX(resp, resplen); return 0; }
static int _vlsctlc_pack_cmd(struct vlsctlc* lsctlc, void* buf, int len) { struct vlsctlc_pack_cmd_desc* desc = lsctlc_pack_cmd_desc; void* len_addr = NULL; int ret = 0; int tsz = 0; int bsz = 0; vassert(lsctlc); vassert(buf); vassert(len > 0); set_uint8(buf + tsz, VLSCTL_VERSION); tsz += sizeof(uint8_t); set_uint8(buf + tsz, (uint8_t)lsctlc->type); tsz += sizeof(uint8_t); set_uint16(len_addr = buf + tsz, 0); tsz += sizeof(uint16_t); set_uint32(buf + tsz, VLSCTL_MAGIC); tsz += sizeof(uint32_t); for (; desc->cmd; desc++) { ret = desc->cmd(lsctlc, buf + tsz, len - tsz); if (ret < 0) { return -1; } bsz += ret; tsz += ret; } *(uint16_t*)len_addr = (uint16_t)bsz; return tsz; }
/** Pack global_id and circ_id; set *tag to the result. (See note on * cpuworker_main for wire format.) */ static void tag_pack(uint8_t *tag, uint64_t chan_id, circid_t circ_id) { /*XXXX RETHINK THIS WHOLE MESS !!!! !NM NM NM NM*/ /*XXXX DOUBLEPLUSTHIS!!!! AS AS AS AS*/ set_uint64(tag, chan_id); set_uint32(tag+8, circ_id); }
static int _aux_vlsctlc_pack_vaddr(void* buf, int len, struct vsockaddr_in* addr) { int tsz = 0; vassert(addr); vassert(buf); vassert(len > 0); tsz += sizeof(uint16_t); // skip family; set_uint16(buf + tsz, addr->addr.sin_port); tsz += sizeof(int16_t); set_uint32(buf + tsz, addr->addr.sin_addr.s_addr); tsz += sizeof(uint32_t); set_uint32(buf + tsz, addr->type); tsz += sizeof(uint32_t); return tsz; }
static void update_difference(int ipv6, uint8_t *d, const tor_addr_t *a, const tor_addr_t *b) { const int n_bytes = ipv6 ? 16 : 4; uint8_t a_tmp[4], b_tmp[4]; const uint8_t *ba, *bb; int i; if (ipv6) { ba = tor_addr_to_in6_addr8(a); bb = tor_addr_to_in6_addr8(b); } else { set_uint32(a_tmp, tor_addr_to_ipv4n(a)); set_uint32(b_tmp, tor_addr_to_ipv4n(b)); ba = a_tmp; bb = b_tmp; } for (i = 0; i < n_bytes; ++i) { d[i] |= ba[i] ^ bb[i]; } }
static void write_children (GString *out, MetaBuilder *builder) { GHashTable *strings; MetaFile *child, *file; GList *l; GList *files; files = g_list_prepend (NULL, builder->root); while (files != NULL) { file = files->data; files = g_list_remove_link (files, files); if (file->children == NULL) continue; /* No children, skip file */ strings = string_block_begin (); if (file->children_pointer != 0) set_uint32 (out, file->children_pointer, out->len); append_uint32 (out, g_list_length (file->children), NULL); for (l = file->children; l != NULL; l = l->next) { child = l->data; /* No mtime, children or metadata, no need for this to be in the file */ if (child->last_changed == 0 && child->children == NULL && child->data == NULL) continue; append_string (out, child->name, strings); append_uint32 (out, 0, &child->children_pointer); append_uint32 (out, 0, &child->metadata_pointer); append_time_t (out, child->last_changed, builder); if (file->children) files = g_list_append (files, child); } string_block_end (out, strings); } }
static gboolean create_new_journal (const char *filename, guint32 random_tag) { char *journal_name; guint32 size_offset; GString *out; gsize pos; gboolean res; journal_name = get_journal_filename (filename, random_tag); out = g_string_new (NULL); /* HEADER */ g_string_append_c (out, 0xda); g_string_append_c (out, 0x1a); g_string_append_c (out, 'j'); g_string_append_c (out, 'o'); g_string_append_c (out, 'u'); g_string_append_c (out, 'r'); /* VERSION */ g_string_append_c (out, MAJOR_JOURNAL_VERSION); g_string_append_c (out, MINOR_JOURNAL_VERSION); append_uint32 (out, random_tag, NULL); append_uint32 (out, 0, &size_offset); append_uint32 (out, 0, NULL); /* Num entries, none so far */ pos = out->len; g_string_set_size (out, NEW_JOURNAL_SIZE); memset (out->str + pos, 0, out->len - pos); set_uint32 (out, size_offset, out->len); res = g_file_set_contents (journal_name, out->str, out->len, NULL); g_free (journal_name); g_string_free (out, TRUE); return res; }
static int build_socks5_resolve_ptr_request(char **out, const void *_addr) { size_t len; const struct in_addr *addr=_addr; len = 12; *out = malloc(len); (*out)[0] = 5; /* SOCKS version 5 */ (*out)[1] = '\xF1'; /* Command: reverse resolve. see doc/socks-extensions.txt*/ (*out)[2] = '\x00'; /* RSV */ (*out)[3] = '\x01'; /* ATYP: IP V4 address: X'01' */ set_uint32((*out)+4, addr->s_addr);/*IP*/ set_uint16((*out)+4+4, 0); /* port */ return len; }
/* Return a srv object that is built with the construction: * SRV = SHA3-256("shared-random" | INT_8(reveal_num) | * INT_4(version) | HASHED_REVEALS | previous_SRV) * This function cannot fail. */ static sr_srv_t * generate_srv(const char *hashed_reveals, uint64_t reveal_num, const sr_srv_t *previous_srv) { char msg[DIGEST256_LEN + SR_SRV_MSG_LEN] = {0}; size_t offset = 0; sr_srv_t *srv; tor_assert(hashed_reveals); /* Add the invariant token. */ memcpy(msg, SR_SRV_TOKEN, SR_SRV_TOKEN_LEN); offset += SR_SRV_TOKEN_LEN; set_uint64(msg + offset, tor_htonll(reveal_num)); offset += sizeof(uint64_t); set_uint32(msg + offset, htonl(SR_PROTO_VERSION)); offset += sizeof(uint32_t); memcpy(msg + offset, hashed_reveals, DIGEST256_LEN); offset += DIGEST256_LEN; if (previous_srv != NULL) { memcpy(msg + offset, previous_srv->value, sizeof(previous_srv->value)); } /* Ok we have our message and key for the HMAC computation, allocate our * srv object and do the last step. */ srv = tor_malloc_zero(sizeof(*srv)); crypto_digest256((char *) srv->value, msg, sizeof(msg), SR_DIGEST_ALG); srv->num_reveals = reveal_num; { /* Debugging. */ char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1]; sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv); log_info(LD_DIR, "SR: Generated SRV: %s", srv_hash_encoded); } return srv; }
/** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) { uint8_t *p, *eop; if (check_extend_cell(cell_in) < 0) return -1; p = payload_out; eop = payload_out + RELAY_PAYLOAD_SIZE; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: { *command_out = RELAY_COMMAND_EXTEND; *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, ntohs(cell_in->orport_ipv4.port)); if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p+6, NTOR_CREATE_MAGIC, 16); memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); } else { memcpy(p+6, cell_in->create_cell.onionskin, TAP_ONIONSKIN_CHALLENGE_LEN); } memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); } break; case RELAY_COMMAND_EXTEND2: { uint8_t n = 2; *command_out = RELAY_COMMAND_EXTEND2; *p++ = n; /* 2 identifiers */ *p++ = SPECTYPE_IPV4; /* First is IPV4. */ *p++ = 6; /* It's 6 bytes long. */ set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, htons(cell_in->orport_ipv4.port)); p += 6; *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */ *p++ = 20; /* It's 20 bytes long */ memcpy(p, cell_in->node_id, DIGEST_LEN); p += 20; /* Now we can send the handshake */ set_uint16(p, htons(cell_in->create_cell.handshake_type)); set_uint16(p+2, htons(cell_in->create_cell.handshake_len)); p += 4; if (cell_in->create_cell.handshake_len > eop - p) return -1; memcpy(p, cell_in->create_cell.onionskin, cell_in->create_cell.handshake_len); p += cell_in->create_cell.handshake_len; *len_out = p - payload_out; } break; default: return -1; } return 0; }
/** * Make an authenticated passphrase-encrypted blob to encode the * <b>input_len</b> bytes in <b>input</b> using the passphrase * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory * to hold the encrypted data, and store a pointer to that memory in * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an * argument to the passphrase-hashing function. */ int crypto_pwbox(uint8_t **out, size_t *outlen_out, const uint8_t *input, size_t input_len, const char *secret, size_t secret_len, unsigned s2k_flags) { uint8_t *result = NULL, *encrypted_portion; size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128); ssize_t result_len; int spec_len; uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; pwbox_encoded_t *enc = NULL; ssize_t enc_len; crypto_cipher_t *cipher; int rv; enc = pwbox_encoded_new(); pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN); spec_len = secret_to_key_make_specifier( pwbox_encoded_getarray_skey_header(enc), S2K_MAXLEN, s2k_flags); if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN)) goto err; pwbox_encoded_setlen_skey_header(enc, spec_len); enc->header_len = spec_len; crypto_rand((char*)enc->iv, sizeof(enc->iv)); pwbox_encoded_setlen_data(enc, encrypted_len); encrypted_portion = pwbox_encoded_getarray_data(enc); set_uint32(encrypted_portion, htonl((uint32_t)input_len)); memcpy(encrypted_portion+4, input, input_len); /* Now that all the data is in position, derive some keys, encrypt, and * digest */ const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys), pwbox_encoded_getarray_skey_header(enc), spec_len, secret, secret_len); if (BUG(s2k_rv < 0)) goto err; cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len); crypto_cipher_free(cipher); result_len = pwbox_encoded_encoded_len(enc); if (BUG(result_len < 0)) goto err; result = tor_malloc(result_len); enc_len = pwbox_encoded_encode(result, result_len, enc); if (BUG(enc_len < 0)) goto err; tor_assert(enc_len == result_len); crypto_hmac_sha256((char*) result + result_len - 32, (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN, (const char*)result, result_len - 32); *out = result; *outlen_out = result_len; rv = 0; goto out; err: /* LCOV_EXCL_START This error case is often unreachable if we're correctly coded, unless somebody adds a new error case somewhere, or unless you're building without scrypto support. - make_specifier can't fail, unless S2K_MAX_LEN is too short. - secret_to_key_derivekey can't really fail unless we're missing scrypt, or the underlying function fails, or we pass it a bogus algorithm or parameters. - pwbox_encoded_encoded_len can't fail unless we're using trunnel incorrectly. - pwbox_encoded_encode can't fail unless we're using trunnel wrong, or it's buggy. */ tor_free(result); rv = -1; /* LCOV_EXCL_STOP */ out: pwbox_encoded_free(enc); memwipe(keys, 0, sizeof(keys)); return rv; }
/** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) { uint8_t *p; if (check_extend_cell(cell_in) < 0) return -1; p = payload_out; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: { *command_out = RELAY_COMMAND_EXTEND; *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, htons(cell_in->orport_ipv4.port)); if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p+6, NTOR_CREATE_MAGIC, 16); memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); } else { memcpy(p+6, cell_in->create_cell.onionskin, TAP_ONIONSKIN_CHALLENGE_LEN); } memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); } break; case RELAY_COMMAND_EXTEND2: { uint8_t n_specifiers = 2; *command_out = RELAY_COMMAND_EXTEND2; extend2_cell_body_t *cell = extend2_cell_body_new(); link_specifier_t *ls; { /* IPv4 specifier first. */ ls = link_specifier_new(); extend2_cell_body_add_ls(cell, ls); ls->ls_type = LS_IPV4; ls->ls_len = 6; ls->un_ipv4_addr = tor_addr_to_ipv4h(&cell_in->orport_ipv4.addr); ls->un_ipv4_port = cell_in->orport_ipv4.port; } { /* Then RSA id */ ls = link_specifier_new(); extend2_cell_body_add_ls(cell, ls); ls->ls_type = LS_LEGACY_ID; ls->ls_len = DIGEST_LEN; memcpy(ls->un_legacy_id, cell_in->node_id, DIGEST_LEN); } if (should_include_ed25519_id_extend_cells(NULL, get_options()) && !ed25519_public_key_is_zero(&cell_in->ed_pubkey)) { /* Then, maybe, the ed25519 id! */ ++n_specifiers; ls = link_specifier_new(); extend2_cell_body_add_ls(cell, ls); ls->ls_type = LS_ED25519_ID; ls->ls_len = 32; memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32); } cell->n_spec = n_specifiers; /* Now, the handshake */ cell->create2 = create2_cell_body_new(); cell->create2->handshake_type = cell_in->create_cell.handshake_type; cell->create2->handshake_len = cell_in->create_cell.handshake_len; create2_cell_body_setlen_handshake_data(cell->create2, cell_in->create_cell.handshake_len); memcpy(create2_cell_body_getarray_handshake_data(cell->create2), cell_in->create_cell.onionskin, cell_in->create_cell.handshake_len); ssize_t len_encoded = extend2_cell_body_encode( payload_out, RELAY_PAYLOAD_SIZE, cell); extend2_cell_body_free(cell); if (len_encoded < 0 || len_encoded > UINT16_MAX) return -1; *len_out = (uint16_t) len_encoded; } break; default: return -1; } return 0; }
static GString * metadata_create_static (MetaBuilder *builder, guint32 *random_tag_out) { GString *out; GHashTable *hash, *key_hash; GHashTableIter iter; char *key; GList *keys, *l; GHashTable *strings; guint32 index; guint32 attributes_pointer; gint64 time_t_min; gint64 time_t_max; guint32 random_tag, root_name; out = g_string_new (NULL); /* HEADER */ g_string_append_c (out, 0xda); g_string_append_c (out, 0x1a); g_string_append_c (out, 'm'); g_string_append_c (out, 'e'); g_string_append_c (out, 't'); g_string_append_c (out, 'a'); /* VERSION */ g_string_append_c (out, MAJOR_VERSION); g_string_append_c (out, MINOR_VERSION); append_uint32 (out, 0, NULL); /* Rotated */ random_tag = g_random_int (); *random_tag_out = random_tag; append_uint32 (out, random_tag, NULL); append_uint32 (out, 0, &builder->root_pointer); append_uint32 (out, 0, &attributes_pointer); time_t_min = 0; time_t_max = 0; metafile_collect_times (builder->root, &time_t_min, &time_t_max); /* Store the base as the min value in use minus one so that 0 is free to mean "not defined" */ time_t_min = time_t_min - 1; /* Pick the base as the minimum, unless that leads to a 32bit overflow */ if (time_t_max - time_t_min > G_MAXUINT32) time_t_min = time_t_max - G_MAXUINT32; builder->time_t_base = time_t_min; append_int64 (out, builder->time_t_base); /* Collect and sort all used keys */ hash = g_hash_table_new (g_str_hash, g_str_equal); metafile_collect_keywords (builder->root, hash); g_hash_table_iter_init (&iter, hash); keys = NULL; while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL)) keys = g_list_prepend (keys, key); g_hash_table_destroy (hash); keys = g_list_sort (keys, (GCompareFunc)strcmp); /* Write keys to file and collect mapping for keys */ set_uint32 (out, attributes_pointer, out->len); key_hash = g_hash_table_new (g_str_hash, g_str_equal); strings = string_block_begin (); append_uint32 (out, g_list_length (keys), NULL); for (l = keys, index = 0; l != NULL; l = l->next, index++) { key = l->data; append_string (out, key, strings); g_hash_table_insert (key_hash, key, GUINT_TO_POINTER (index)); } string_block_end (out, strings); /* update root pointer */ set_uint32 (out, builder->root_pointer, out->len); /* Root name */ append_uint32 (out, 0, &root_name); /* Root child pointer */ append_uint32 (out, 0, &builder->root->children_pointer); /* Root metadata pointer */ append_uint32 (out, 0, &builder->root->metadata_pointer); /* Root last changed */ append_uint32 (out, builder->root->last_changed, NULL); /* Root name */ set_uint32 (out, root_name, out->len); g_string_append_len (out, "/", 2); /* Pad to 32bit */ while (out->len % 4 != 0) g_string_append_c (out, 0); write_children (out, builder); write_metadata (out, builder, key_hash); g_hash_table_destroy (key_hash); g_list_free (keys); return out; }