+cp
+ return send_chal_reply(c);
+}
+
+int send_chal_reply(connection_t *c)
+{
+ char hash[SHA_DIGEST_LENGTH*2+1];
+cp
+ /* Calculate the hash from the challenge we received */
+
+ SHA1(c->mychallenge, RSA_size(myself->connection->rsa_key), hash);
+
+ /* Convert the hash to a hexadecimal formatted string */
+
+ bin2hex(hash,hash,SHA_DIGEST_LENGTH);
+ hash[SHA_DIGEST_LENGTH*2] = '\0';
+
+ /* Send the reply */
+
+cp
+ return send_request(c, "%d %s", CHAL_REPLY, hash);
+}
+
+int chal_reply_h(connection_t *c)
+{
+ char hishash[MAX_STRING_SIZE];
+ char myhash[SHA_DIGEST_LENGTH];
+cp
+ if(sscanf(c->buffer, "%*d "MAX_STRING, hishash) != 1)
+ {
+ syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name, c->hostname);
+ return -1;
+ }
+
+ /* Check if the length of the hash is all right */
+
+ if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
+ {
+ syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length"));
+ return -1;
+ }
+
+ /* Convert the hash to binary format */
+
+ hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
+
+ /* Calculate the hash from the challenge we sent */
+
+ SHA1(c->hischallenge, RSA_size(c->rsa_key), myhash);
+
+ /* Verify the incoming hash with the calculated hash */
+
+ if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
+ {
+ syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply"));
+ if(debug_lvl >= DEBUG_SCARY_THINGS)
+ {
+ bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
+ hishash[SHA_DIGEST_LENGTH*2] = '\0';
+ syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
+ }
+ return -1;
+ }
+
+ /* Identity has now been positively verified.
+ Send an acknowledgement with the rest of the information needed.
+ */
+
+ c->allow_request = ACK;
+cp
+ return send_ack(c);
+}
+
+int send_ack(connection_t *c)
+{
+ /* ACK message contains rest of the information the other end needs
+ to create node_t and edge_t structures. */
+cp
+ return send_request(c, "%d %d", ACK, myself->port);
+}
+
+int ack_h(connection_t *c)
+{
+ port_t port;
+ node_t *n;
+ subnet_t *s;
+ avl_node_t *node, *node2;
+cp
+ if(sscanf(c->buffer, "%*d %hd", &port) != 1)
+ {
+ syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, c->hostname);
+ return -1;
+ }
+
+ /* Check if we already have a node_t for him */
+
+ n = lookup_node(c->name);
+
+ if(!n)
+ {
+ n = new_node();
+ n->name = xstrdup(c->name);
+ n->hostname = xstrdup(c->hostname);
+ n->port = port;
+
+ /* FIXME: Also check if no other tinc daemon uses the same IP and port for UDP traffic */
+
+ node_add(n);
+ }
+ else
+ {
+ if(n->connection)
+ {
+ /* Oh dear, we already have a connection to this node. */
+ syslog(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->name, n->hostname);
+ terminate_connection(n->connection, 0);
+ }
+
+ /* FIXME: check if information in existing node matches that of the other end of this connection */
+ }
+
+ n->connection = c;
+ c->node = n;
+
+ /* Check some options
+
+ if((cfg = get_config_val(c->config, config_indirectdata)))
+ {
+ if(cfg->data.val == stupid_true)
+ c->options |= OPTION_INDIRECT;
+ }
+
+ if((cfg = get_config_val(c->config, config_tcponly)))
+ {
+ if(cfg->data.val == stupid_true)
+ c->options |= OPTION_TCPONLY;
+ }
+
+ if((myself->options | c->options) & OPTION_INDIRECT)
+ c->via = myself;
+ else
+ c->via = c;
+
+ */
+
+ /* Create a edge_t for this connection */
+
+ c->edge = new_edge();