X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcpacket.c;h=6dbb69bb44ca4d92751cdd58b439a69962a82d50;hb=52e57c880aba9c5e89f59d962eb9af75670b76e0;hp=94fcffc71146e16bdbd73dfedde4d51186920f9f;hpb=c1c904ec2af21f1c2b272d790b38d93824af5352;p=silc.git diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index 94fcffc7..6dbb69bb 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -306,7 +306,7 @@ static inline SilcBool silc_packet_stream_read(SilcPacketStream ps, inbuf = silc_dlist_get(ps->sc->inbufs); if (!inbuf) { /* Allocate new data input buffer */ - inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31); + inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65); if (!inbuf) { silc_mutex_unlock(ps->lock); return FALSE; @@ -623,6 +623,60 @@ void silc_packet_engine_stop(SilcPacketEngine engine) silc_free(engine); } +static const char *packet_error[] = { + "Cannot read from stream", + "Cannot write to stream", + "Packet MAC failed", + "Packet decryption failed", + "Unknown SID", + "Packet is malformed", + "System out of memory", +}; + +/* Return packet error string */ + +const char *silc_packet_error_string(SilcPacketError error) +{ + if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY) + return ""; + return packet_error[error]; +} + +/* Return list of packet streams in the engine */ + +SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine) +{ + SilcDList list; + SilcPacketStream ps; + + list = silc_dlist_init(); + if (!list) + return NULL; + + silc_mutex_lock(engine->lock); + silc_list_start(engine->streams); + while ((ps = silc_list_get(engine->streams))) { + silc_packet_stream_ref(ps); + silc_dlist_add(list, ps); + } + silc_mutex_unlock(engine->lock); + + return list; +} + +/* Free list returned by silc_packet_engine_get_streams */ + +void silc_packet_engine_free_streams_list(SilcDList streams) +{ + SilcPacketStream ps; + + silc_dlist_start(streams); + while ((ps = silc_dlist_get(streams))) + silc_packet_stream_unref(ps); + + silc_dlist_uninit(streams); +} + /* Create new packet stream */ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine, @@ -677,7 +731,7 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine, ps->sc->schedule = schedule; /* Allocate data input buffer */ - inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31); + inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65); if (!inbuf) { silc_free(ps->sc); ps->sc = NULL; @@ -825,6 +879,8 @@ SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream, void silc_packet_stream_destroy(SilcPacketStream stream) { + SilcPacketEngine engine; + if (!stream) return; @@ -841,17 +897,17 @@ void silc_packet_stream_destroy(SilcPacketStream stream) if (!stream->udp) { /* Delete from engine */ - silc_mutex_lock(stream->sc->engine->lock); - silc_list_del(stream->sc->engine->streams, stream); + engine = stream->sc->engine; + silc_mutex_lock(engine->lock); + silc_list_del(engine->streams, stream); /* Remove per scheduler context, if it is not used anymore */ if (stream->sc) { stream->sc->stream_count--; if (!stream->sc->stream_count) - silc_hash_table_del(stream->sc->engine->contexts, - stream->sc->schedule); + silc_hash_table_del(engine->contexts, stream->sc->schedule); } - silc_mutex_unlock(stream->sc->engine->lock); + silc_mutex_unlock(engine->lock); /* Destroy the underlaying stream */ if (stream->stream) @@ -859,11 +915,13 @@ void silc_packet_stream_destroy(SilcPacketStream stream) } else { /* Delete from UDP remote hash table */ char tuple[64]; - silc_snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port, - stream->remote_udp->remote_ip); - silc_mutex_lock(stream->sc->engine->lock); - silc_hash_table_del(stream->sc->engine->udp_remote, tuple); - silc_mutex_unlock(stream->sc->engine->lock); + engine = stream->sc->engine; + silc_snprintf(tuple, sizeof(tuple), "%d%s", + stream->remote_udp->remote_port, + stream->remote_udp->remote_ip); + silc_mutex_lock(engine->lock); + silc_hash_table_del(engine->udp_remote, tuple); + silc_mutex_unlock(engine->lock); silc_free(stream->remote_udp->remote_ip); silc_free(stream->remote_udp); @@ -914,6 +972,13 @@ void silc_packet_stream_destroy(SilcPacketStream stream) silc_free(stream); } +/* Return TRUE if the stream is valid */ + +SilcBool silc_packet_stream_is_valid(SilcPacketStream stream) +{ + return stream->destroyed == FALSE; +} + /* Marks as router stream */ void silc_packet_stream_set_router(SilcPacketStream stream) @@ -1257,11 +1322,11 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream, if (!src_id && !dst_id) return FALSE; - SILC_LOG_DEBUG(("Setting new IDs to packet stream")); - silc_mutex_lock(stream->lock); if (src_id) { + SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream)); + silc_free(stream->src_id); if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) { silc_mutex_unlock(stream->lock); @@ -1277,6 +1342,8 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream, } if (dst_id) { + SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream)); + silc_free(stream->dst_id); if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) { silc_mutex_unlock(stream->lock); @@ -1296,6 +1363,31 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream, return TRUE; } +/* Return IDs from the packet stream */ + +SilcBool silc_packet_get_ids(SilcPacketStream stream, + SilcBool *src_id_set, SilcID *src_id, + SilcBool *dst_id_set, SilcID *dst_id) +{ + if (src_id && stream->src_id) + if (!silc_id_str2id2(stream->src_id, stream->src_id_len, + stream->src_id_type, src_id)) + return FALSE; + + if (stream->src_id && src_id_set) + *src_id_set = TRUE; + + if (dst_id && stream->dst_id) + if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len, + stream->dst_id_type, dst_id)) + return FALSE; + + if (stream->dst_id && dst_id_set) + *dst_id_set = TRUE; + + return TRUE; +} + /* Adds Security ID (SID) */ SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid) @@ -1373,12 +1465,15 @@ static inline void silc_packet_send_ctr_increment(SilcPacketStream stream, unsigned char *ret_iv) { unsigned char *iv = silc_cipher_get_iv(cipher); - SilcUInt32 pc; + SilcUInt32 pc1, pc2; - /* Increment packet counter */ - SILC_GET32_MSB(pc, iv + 8); - pc++; - SILC_PUT32_MSB(pc, iv + 8); + /* Increment 64-bit packet counter */ + SILC_GET32_MSB(pc1, iv + 4); + SILC_GET32_MSB(pc2, iv + 8); + if (++pc2 == 0) + ++pc1; + SILC_PUT32_MSB(pc1, iv + 4); + SILC_PUT32_MSB(pc2, iv + 8); /* Reset block counter */ memset(iv + 12, 0, 4); @@ -1390,7 +1485,7 @@ static inline void silc_packet_send_ctr_increment(SilcPacketStream stream, ret_iv[1] = ret_iv[0] + iv[4]; ret_iv[2] = ret_iv[0] ^ ret_iv[1]; ret_iv[3] = ret_iv[0] + ret_iv[2]; - SILC_PUT32_MSB(pc, ret_iv + 4); + SILC_PUT32_MSB(pc2, ret_iv + 4); SILC_LOG_HEXDUMP(("IV"), ret_iv, 8); /* Set new nonce to counter block */ @@ -1461,10 +1556,8 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream, type and flags, and calculate correct length. Private messages with private keys and channel messages are special packets as their payload is encrypted already. */ - if ((type == SILC_PACKET_PRIVATE_MESSAGE && - flags & SILC_PACKET_FLAG_PRIVMSG_KEY) || - type == SILC_PACKET_CHANNEL_MESSAGE) { - + if (type == SILC_PACKET_PRIVATE_MESSAGE && + flags & SILC_PACKET_FLAG_PRIVMSG_KEY) { /* Padding is calculated from header + IDs */ if (!ctr) SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len + @@ -1473,8 +1566,26 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream, /* Length to encrypt, header + IDs + padding. */ enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len + padlen + psnlen); - } else { + } else if (type == SILC_PACKET_CHANNEL_MESSAGE) { + if (stream->sc->engine->local_is_router && stream->is_router) { + /* Channel messages between routers are encrypted as normal packets. + Padding is calculated from true length of the packet. */ + if (!ctr) + SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen); + + enclen += padlen + psnlen; + } else { + /* Padding is calculated from header + IDs */ + if (!ctr) + SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len + + psnlen), block_len, padlen); + + /* Length to encrypt, header + IDs + padding. */ + enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len + + padlen + psnlen); + } + } else { /* Padding is calculated from true length of the packet */ if (flags & SILC_PACKET_FLAG_LONG_PAD) SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen); @@ -1532,6 +1643,7 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream, /* Encrypt the packet */ if (silc_likely(cipher)) { SILC_LOG_DEBUG(("Encrypting packet")); + silc_cipher_set_iv(cipher, NULL); if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen, packet.data + ivlen, enclen, NULL))) { @@ -1722,16 +1834,19 @@ static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream, unsigned char *iv, unsigned char *packet_iv) { - SilcUInt32 pc; + SilcUInt32 pc1, pc2; /* If IV Included flag, set the IV from packet to block counter. */ if (stream->iv_included) { memcpy(iv + 4, packet_iv, 8); } else { - /* Increment packet counter */ - SILC_GET32_MSB(pc, iv + 8); - pc++; - SILC_PUT32_MSB(pc, iv + 8); + /* Increment 64-bit packet counter. */ + SILC_GET32_MSB(pc1, iv + 4); + SILC_GET32_MSB(pc2, iv + 8); + if (++pc2 == 0) + ++pc1; + SILC_PUT32_MSB(pc1, iv + 4); + SILC_PUT32_MSB(pc2, iv + 8); } /* Reset block counter */ @@ -1857,8 +1972,8 @@ static inline SilcBool silc_packet_parse(SilcPacket packet) silc_buffer_len(buffer)), buffer->head, silc_buffer_headlen(buffer) + silc_buffer_len(buffer)); - SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type, - silc_get_packet_name(packet->type))); + SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type, + silc_get_packet_name(packet->type), packet->flags)); return TRUE; } @@ -2049,8 +2164,9 @@ static void silc_packet_read_process(SilcPacketStream stream) silc_packet_receive_ctr_increment(stream, iv, NULL); } - silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, - block_len, iv); + if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) + silc_cipher_set_iv(cipher, NULL); + silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv); header = tmp; if (stream->iv_included) { @@ -2224,6 +2340,9 @@ typedef struct { SilcMutex wait_lock; SilcCond wait_cond; SilcList packet_queue; + unsigned char id[28]; + unsigned int id_type : 2; + unsigned int id_len : 5; unsigned int stopped : 1; } *SilcPacketWait; @@ -2238,6 +2357,13 @@ silc_packet_wait_packet_receive(SilcPacketEngine engine, { SilcPacketWait pw = callback_context; + /* If source ID is specified check for it */ + if (pw->id_len) { + if (pw->id_type != packet->src_id_type || + memcmp(pw->id, packet->src_id, pw->id_len)) + return FALSE; + } + /* Signal the waiting thread for a new packet */ silc_mutex_lock(pw->wait_lock); @@ -2256,7 +2382,8 @@ silc_packet_wait_packet_receive(SilcPacketEngine engine, /* Initialize packet waiting */ -void *silc_packet_wait_init(SilcPacketStream stream, ...) +void *silc_packet_wait_init(SilcPacketStream stream, + const SilcID *source_id, ...) { SilcPacketWait pw; SilcBool ret; @@ -2278,7 +2405,7 @@ void *silc_packet_wait_init(SilcPacketStream stream, ...) } /* Link to the packet stream for the requested packet types */ - va_start(ap, stream); + va_start(ap, source_id); ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw, 10000000, ap); va_end(ap); @@ -2292,6 +2419,14 @@ void *silc_packet_wait_init(SilcPacketStream stream, ...) /* Initialize packet queue */ silc_list_init(pw->packet_queue, struct SilcPacketStruct, next); + if (source_id) { + SilcUInt32 id_len; + silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id, + sizeof(pw->id), &id_len); + pw->id_type = source_id->type; + pw->id_len = id_len; + } + return (void *)pw; } @@ -2307,6 +2442,7 @@ void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream) pw->stopped = TRUE; silc_cond_broadcast(pw->wait_cond); silc_mutex_unlock(pw->wait_lock); + silc_thread_yield(); /* Re-acquire lock and free resources */ silc_mutex_lock(pw->wait_lock); @@ -2495,7 +2631,7 @@ int silc_packet_wrap_write(SilcStream stream, const unsigned char *data, SilcPacketWrapperStream pws = stream; SilcBool ret = FALSE; - /* Call decoder if set */ + /* Call encoder if set */ if (pws->coder) { silc_buffer_reset(pws->encbuf); ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf, @@ -2626,18 +2762,14 @@ SilcStream silc_packet_stream_wrap(SilcPacketStream stream, if (pws->blocking) { /* Blocking mode. Use packet waiter to do the thing. */ - pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1); + pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1); if (!pws->waiter) { silc_free(pws); return NULL; } } else { /* Non-blocking mode */ - if (!silc_mutex_alloc(&pws->lock)) { - silc_free(pws); - return NULL; - } - + silc_mutex_alloc(&pws->lock); silc_list_init(pws->in_queue, struct SilcPacketStruct, next); }