5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 * Created: Fri Jul 25 18:52:14 1997
24 #include "silcincludes.h"
26 /******************************************************************************
28 Packet Sending Routines
30 ******************************************************************************/
32 /* Actually sends the packet. This flushes the connections outgoing data
33 buffer. If data is sent directly to the network this returns the bytes
34 written, if error occured this returns -1 and if the data could not
35 be written directly to the network at this time this returns -2, in
36 which case the data should be queued by the caller and sent at some
37 later time. If `force_send' is TRUE this attempts to write the data
38 directly to the network, if FALSE, this returns -2. */
40 int silc_packet_send(SilcSocketConnection sock, bool force_send)
42 SILC_LOG_DEBUG(("Sending packet to %s:%d [%s]", sock->hostname,
44 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
45 sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
46 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
49 /* Send now if forced to do so */
50 if (force_send == TRUE) {
53 SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
55 /* Write to network */
56 ret = silc_socket_write(sock);
59 SILC_LOG_ERROR(("Error sending packet, dropped"));
64 SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
67 SILC_LOG_DEBUG(("Packet in queue"));
72 /* Encrypts a packet. This also creates HMAC of the packet before
73 encryption and adds the HMAC at the end of the buffer. This assumes
74 that there is enough free space at the end of the buffer to add the
75 computed HMAC. This is the normal way of encrypting packets, if some
76 other process of HMAC computing and encryption is needed this function
79 void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence,
80 SilcBuffer buffer, uint32 len)
82 unsigned char mac[32];
85 /* Compute HMAC. This assumes that HMAC is created from the entire
86 data area thus this uses the length found in buffer, not the length
93 /* XXX Backwards support for old MAC computation.
94 XXX Remove in 0.7.x */
95 if (!silc_hmac_get_b(hmac)) {
96 SILC_PUT32_MSB(sequence, psn);
97 silc_hmac_update(hmac, psn, 4);
100 silc_hmac_update(hmac, buffer->data, buffer->len);
101 silc_hmac_final(hmac, mac, &mac_len);
102 silc_buffer_put_tail(buffer, mac, mac_len);
103 memset(mac, 0, sizeof(mac));
106 /* Encrypt the data area of the packet. */
108 SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d",
109 cipher->cipher->name, len));
110 /* XXX Backwards support for 0.5.x
111 XXX Remove in 0.7.x */
112 if (hmac && silc_hmac_get_b(hmac))
113 silc_cipher_encrypt(cipher, buffer->data + 2, buffer->data + 2,
114 len - 1, cipher->iv);
116 silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, cipher->iv);
119 /* Pull the HMAC into the visible data area in the buffer */
121 silc_buffer_pull_tail(buffer, mac_len);
124 /* Assembles a new packet to be ready for send out. The buffer sent as
125 argument must include the data to be sent and it must not be encrypted.
126 The packet also must have enough free space so that the SILC header
127 and padding maybe added to the packet. The packet is encrypted after
128 this function has returned.
130 The buffer sent as argument should be something like following:
132 --------------------------------------------
133 | head | data | tail |
134 --------------------------------------------
138 So that the SILC header and 1 - 16 bytes of padding can fit to
139 the buffer. After assembly the buffer might look like this:
141 --------------------------------------------
143 --------------------------------------------
145 Start of assembled packet
147 Packet construct is as follows:
150 2 bytes Payload length
153 2 bytes Source ID Length
154 2 bytes Destination ID Length
155 1 byte Source ID Type
157 1 byte Destination ID Type
158 n bytes Destination ID
164 All fields in the packet will be authenticated by MAC. The MAC is
165 not computed here, it must be computed separately before encrypting
170 void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher)
172 unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
173 int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
176 SILC_LOG_DEBUG(("Assembling outgoing packet"));
178 /* Get the true length of the packet. This is saved as payload length
179 into the packet header. This does not include the length of the
182 ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN +
183 ctx->src_id_len + ctx->dst_id_len;
185 /* Calculate the length of the padding. The padding is calculated from
186 the data that will be encrypted. */
188 ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len);
189 /* XXX backwards support for 0.5.x
190 XXX remove in 0.7.x */
192 ctx->padlen = SILC_PACKET_PADLEN2(ctx->truelen, block_len);
195 /* Put the start of the data section to the right place. */
196 silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN +
197 ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
199 /* Get random padding */
201 for (i = 0; i < ctx->padlen; i++) tmppad[i] = silc_rng_global_get_byte();
203 /* XXX: For testing - to be removed */
204 memset(tmppad, 65, sizeof(tmppad));
207 /* Create the packet. This creates the SILC header and adds padding,
208 rest of the buffer remains as it is. */
209 silc_buffer_format(ctx->buffer,
210 SILC_STR_UI_SHORT(ctx->truelen),
211 SILC_STR_UI_CHAR(ctx->flags),
212 SILC_STR_UI_CHAR(ctx->type),
213 SILC_STR_UI_SHORT(ctx->src_id_len),
214 SILC_STR_UI_SHORT(ctx->dst_id_len),
215 SILC_STR_UI_CHAR(ctx->src_id_type),
216 SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
217 SILC_STR_UI_CHAR(ctx->dst_id_type),
218 SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
219 SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
222 SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len),
223 ctx->buffer->data, ctx->buffer->len);
225 SILC_LOG_DEBUG(("Outgoing packet assembled"));
228 /* Prepare outgoing data buffer for packet sending. This moves the data
229 area so that new packet may be added into it. If needed this allocates
230 more space to the buffer. This handles directly the connection's
231 outgoing buffer in SilcSocketConnection object. */
233 void silc_packet_send_prepare(SilcSocketConnection sock,
240 totlen = header_len + padlen + data_len;
242 /* Prepare the outgoing buffer for packet sending. */
244 /* Allocate new buffer. This is done only once per connection. */
245 SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
247 if (totlen > SILC_PACKET_DEFAULT_SIZE)
248 sock->outbuf = silc_buffer_alloc(totlen);
250 sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
251 silc_buffer_pull_tail(sock->outbuf, totlen);
252 silc_buffer_pull(sock->outbuf, header_len + padlen);
254 if (SILC_IS_OUTBUF_PENDING(sock)) {
255 /* There is some pending data in the buffer. */
257 /* Allocate more space if needed */
258 if ((sock->outbuf->end - sock->outbuf->tail) <
260 SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
261 sock->outbuf = silc_buffer_realloc(sock->outbuf,
262 sock->outbuf->truelen +
266 oldlen = sock->outbuf->len;
267 silc_buffer_pull_tail(sock->outbuf, totlen);
268 silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
270 /* Buffer is free for use */
271 silc_buffer_clear(sock->outbuf);
273 /* Allocate more space if needed */
274 if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + 20)) {
275 SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
276 sock->outbuf = silc_buffer_realloc(sock->outbuf,
277 sock->outbuf->truelen +
281 silc_buffer_pull_tail(sock->outbuf, totlen);
282 silc_buffer_pull(sock->outbuf, header_len + padlen);
287 /******************************************************************************
289 Packet Reception Routines
291 ******************************************************************************/
293 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
294 uint32 sequence, SilcBuffer buffer,
297 /* Receives packet from network and reads the data into connection's
298 incoming data buffer. If the data was read directly this returns the
299 read bytes, if error occured this returns -1, if the data could not
300 be read directly at this time this returns -2 in which case the data
301 should be read again at some later time, or If EOF occured this returns
304 int silc_packet_receive(SilcSocketConnection sock)
308 SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
310 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
311 sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
312 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
315 /* Read some data from connection */
316 ret = silc_socket_read(sock);
321 /* Processes and decrypts the incmoing data, and calls parser callback
322 for each received packet that will handle the actual packet parsing.
323 If more than one packet was received this calls the parser multiple
324 times. The parser callback will get context SilcPacketParserContext
325 that includes the packet and the `parser_context' sent to this
328 The `local_is_router' indicates whether the caller is router server
329 in which case the receiving process of a certain packet types may
330 be special. Normal server and client must set it to FALSE. The
331 SilcPacketParserContext will indicate also whether the received
332 packet was normal or special packet. */
334 void silc_packet_receive_process(SilcSocketConnection sock,
335 bool local_is_router,
336 SilcCipher cipher, SilcHmac hmac,
338 SilcPacketParserCallback parser,
339 void *parser_context)
341 SilcPacketParserContext *parse_ctx;
342 int packetlen, paddedlen, mac_len = 0;
343 int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
345 if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
349 mac_len = silc_hmac_len(hmac);
351 /* Parse the packets from the data */
352 while (sock->inbuf->len > 0) {
354 /* Decrypt first 16 bytes of the packet */
355 if (!SILC_IS_INBUF_PENDING(sock) && cipher) {
356 /* XXX backwards support for 0.5.x
357 XXX remove in 0.7.x */
359 silc_cipher_decrypt(cipher, sock->inbuf->data + 2,
360 sock->inbuf->data + 2,
361 SILC_PACKET_MIN_HEADER_LEN, cipher->iv);
363 silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data,
364 SILC_PACKET_MIN_HEADER_LEN, cipher->iv);
367 /* Get packet lenght and full packet length with padding */
368 SILC_PACKET_LENGTH(sock->inbuf, packetlen);
369 /* XXX backwards support for 0.5.x
370 XXX remove in 0.7.x */
371 if (cipher && cipher->back) {
372 paddedlen = packetlen + SILC_PACKET_PADLEN2(packetlen, block_len);
375 paddedlen = packetlen + SILC_PACKET_PADLEN(packetlen, block_len);
379 if (packetlen < SILC_PACKET_MIN_LEN) {
380 SILC_LOG_DEBUG(("Received invalid packet, dropped"));
381 silc_buffer_clear(sock->inbuf);
385 if (sock->inbuf->len < paddedlen + mac_len) {
386 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"
387 "(%d < %d)", sock->inbuf->len, paddedlen + mac_len));
388 SILC_SET_INBUF_PENDING(sock);
392 SILC_UNSET_INBUF_PENDING(sock);
393 parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
394 parse_ctx->packet = silc_packet_context_alloc();
395 parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
396 parse_ctx->packet->sequence = sequence++;
397 parse_ctx->sock = sock;
398 parse_ctx->context = parser_context;
400 silc_buffer_pull_tail(parse_ctx->packet->buffer,
401 SILC_BUFFER_END(parse_ctx->packet->buffer));
402 silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data,
403 paddedlen + mac_len);
405 SILC_LOG_HEXDUMP(("Incoming packet (%d) (%d bytes decrypted), len %d",
406 sequence - 1, block_len, paddedlen + mac_len),
407 sock->inbuf->data, paddedlen + mac_len);
409 /* Check whether this is normal or special packet */
410 if (local_is_router) {
411 if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
412 (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
413 parse_ctx->normal = FALSE;
414 else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE ||
415 (sock->inbuf->data[3] == SILC_PACKET_CHANNEL_MESSAGE &&
416 sock->type == SILC_SOCKET_TYPE_ROUTER))
417 parse_ctx->normal = TRUE;
419 if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
420 (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
421 parse_ctx->normal = FALSE;
422 else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE)
423 parse_ctx->normal = TRUE;
426 /* Decrypt rest of the packet */
428 silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence,
429 parse_ctx->packet->buffer, parse_ctx->normal);
431 /* Call the parser */
433 (*parser)(parse_ctx, parser_context);
435 /* Pull the packet from inbuf thus we'll get the next one
437 silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
440 SILC_LOG_DEBUG(("Clearing inbound buffer"));
441 silc_buffer_clear(sock->inbuf);
444 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
445 after packet has been totally decrypted and parsed. */
447 static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
452 unsigned char mac[32], psn[4];
455 SILC_LOG_DEBUG(("Verifying MAC"));
457 /* Compute HMAC of packet */
459 memset(mac, 0, sizeof(mac));
460 silc_hmac_init(hmac);
462 /* XXX Backwards support for old MAC computation.
463 XXX Remove in 0.7.x */
464 if (!silc_hmac_get_b(hmac)) {
465 SILC_PUT32_MSB(sequence, psn);
466 silc_hmac_update(hmac, psn, 4);
469 silc_hmac_update(hmac, buffer->data, buffer->len);
470 silc_hmac_final(hmac, mac, &mac_len);
472 /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
473 if (memcmp(mac, buffer->tail, mac_len)) {
474 SILC_LOG_ERROR(("MAC failed"));
479 SILC_LOG_DEBUG(("MAC is Ok"));
480 memset(mac, 0, sizeof(mac));
486 /* Decrypts rest of the packet (after decrypting just the SILC header).
487 After calling this function the packet is ready to be parsed by calling
488 silc_packet_parse. If everything goes without errors this returns TRUE,
489 if packet is malformed this returns FALSE. */
491 static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
496 /* Pull MAC from packet before decryption */
498 if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
499 silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
501 SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
506 SILC_LOG_DEBUG(("Decrypting rest of the packet"));
508 /* Decrypt rest of the packet */
509 silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
510 /* XXX backwards support for 0.5.x
511 XXX remove in 0.7.x */
513 silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2,
517 silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len,
519 silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
521 SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
522 buffer->data, buffer->len);
528 /* Decrypts rest of the SILC Packet header that has been decrypted partly
529 already. This decrypts the padding of the packet also. After calling
530 this function the packet is ready to be parsed by calling function
531 silc_packet_parse. This is used in special packet reception (protocol
532 defines the way of decrypting special packets). */
534 static int silc_packet_decrypt_rest_special(SilcCipher cipher,
538 /* Decrypt rest of the header plus padding */
540 uint16 truelen, len1, len2, padlen, blocklen;
542 /* Pull MAC from packet before decryption */
544 if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
545 silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
547 SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
552 SILC_LOG_DEBUG(("Decrypting rest of the header"));
554 SILC_GET16_MSB(len1, &buffer->data[4]);
555 SILC_GET16_MSB(len2, &buffer->data[6]);
557 blocklen = silc_cipher_get_block_len(cipher);
558 truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
560 /* XXX backwards support for 0.5.x
561 XXX remove in 0.7.x */
563 padlen = SILC_PACKET_PADLEN2(truelen, blocklen);
564 len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN);
566 silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
568 if (len1 - 2 > buffer->len) {
569 SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
574 silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2,
575 len1 - 2, cipher->iv);
577 blocklen = silc_cipher_get_block_len(cipher);
578 truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
579 padlen = SILC_PACKET_PADLEN(truelen, blocklen);
580 len1 = (truelen + padlen) - SILC_PACKET_MIN_HEADER_LEN;
582 silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
584 if (len1 > buffer->len) {
585 SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
590 silc_cipher_decrypt(cipher, buffer->data, buffer->data, len1, cipher->iv);
592 silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
598 /* Decrypts a packet. This assumes that typical SILC packet is the
599 packet to be decrypted and thus checks for normal and special SILC
600 packets and can handle both of them. This also computes and checks
601 the HMAC of the packet. If any other special or customized decryption
602 processing is required this function cannot be used. This returns
603 -1 on error, 0 when packet is normal packet and 1 when the packet
604 is special and requires special processing.
606 The `check_packet' is a callback funtion that this function will
607 call. The callback relates to the checking whether the packet is
608 normal packet or special packet and how it should be processed. If
609 the callback return TRUE the packet is normal and FALSE if the packet
610 is special and requires special procesing. */
612 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
613 uint32 sequence, SilcBuffer buffer,
616 /* If the packet type is not any special type lets decrypt rest
617 of the packet here. */
618 if (normal == TRUE) {
619 /* Normal packet, decrypt rest of the packet */
620 if (!silc_packet_decrypt_rest(cipher, hmac, buffer))
624 if (!silc_packet_check_mac(hmac, buffer, sequence))
629 /* Packet requires special handling, decrypt rest of the header.
630 This only decrypts. */
631 if (!silc_packet_decrypt_rest_special(cipher, hmac, buffer))
635 if (!silc_packet_check_mac(hmac, buffer, sequence))
642 /* Parses the packet. This is called when a whole packet is ready to be
643 parsed. The buffer sent must be already decrypted before calling this
644 function. The len argument must be the true length of the packet. This
645 function returns the type of the packet. The data section of the
646 buffer is parsed, not head or tail sections. */
648 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
650 SilcBuffer buffer = ctx->buffer;
652 int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
654 SILC_LOG_DEBUG(("Parsing incoming packet"));
656 /* Check the length of the buffer */
657 if (buffer->len < SILC_PACKET_MIN_LEN) {
658 SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
659 return SILC_PACKET_NONE;
662 /* Parse the buffer. This parses the SILC header of the packet. */
663 len = silc_buffer_unformat(buffer,
664 SILC_STR_UI_SHORT(&ctx->truelen),
665 SILC_STR_UI_CHAR(&ctx->flags),
666 SILC_STR_UI_CHAR(&ctx->type),
667 SILC_STR_UI_SHORT(&ctx->src_id_len),
668 SILC_STR_UI_SHORT(&ctx->dst_id_len),
669 SILC_STR_UI_CHAR(&ctx->src_id_type),
672 return SILC_PACKET_NONE;
674 if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
675 ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
676 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
677 ctx->src_id_len, ctx->dst_id_len));
678 return SILC_PACKET_NONE;
681 /* Calculate length of padding in packet */
682 ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len);
684 silc_buffer_pull(buffer, len);
685 ret = silc_buffer_unformat(buffer,
686 SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
688 SILC_STR_UI_CHAR(&ctx->dst_id_type),
689 SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
691 SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
694 return SILC_PACKET_NONE;
696 /* XXX backwards support for 0.5.x
697 XXX remove in 0.7.x */
698 silc_buffer_pull(buffer,
699 ctx->src_id_len + 1 + ctx->dst_id_len + ctx->padlen);
700 SILC_LOG_DEBUG(("**************** %d", buffer->len));
701 if (buffer->len == 2)
703 silc_buffer_push(buffer, ret);
705 silc_buffer_push(buffer, len);
707 SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
708 ctx->buffer->data, ctx->buffer->len);
710 /* Pull SILC header and padding from packet */
711 silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
712 ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
714 SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
719 /* Perform special SILC Packet header parsing. This is required to some
720 packet types that have the data payload encrypted with different key
721 than the header area plus padding of the packet. Hence, this parses
722 the header in a way that it does not take the data area into account
723 and parses the header and padding area only. */
725 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
728 SilcBuffer buffer = ctx->buffer;
729 int len, tmplen, ret;
730 int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
732 SILC_LOG_DEBUG(("Parsing incoming packet"));
734 /* Check the length of the buffer */
735 if (buffer->len < SILC_PACKET_MIN_LEN) {
736 SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
737 return SILC_PACKET_NONE;
740 /* Parse the buffer. This parses the SILC header of the packet. */
741 len = silc_buffer_unformat(buffer,
742 SILC_STR_UI_SHORT(&ctx->truelen),
743 SILC_STR_UI_CHAR(&ctx->flags),
744 SILC_STR_UI_CHAR(&ctx->type),
745 SILC_STR_UI_SHORT(&ctx->src_id_len),
746 SILC_STR_UI_SHORT(&ctx->dst_id_len),
747 SILC_STR_UI_CHAR(&ctx->src_id_type),
750 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
751 return SILC_PACKET_NONE;
754 if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
755 ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
756 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
757 ctx->src_id_len, ctx->dst_id_len));
758 return SILC_PACKET_NONE;
761 /* Calculate length of padding in packet. As this is special packet
762 the data area is not used in the padding calculation as it won't
763 be decrypted by the caller. */
764 tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len;
765 /* XXX backwards support for 0.5.x
766 XXX remove in 0.7.x */
768 ctx->padlen = SILC_PACKET_PADLEN2(tmplen, block_len);
770 ctx->padlen = SILC_PACKET_PADLEN(tmplen, block_len);
772 silc_buffer_pull(buffer, len);
773 ret = silc_buffer_unformat(buffer,
774 SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
776 SILC_STR_UI_CHAR(&ctx->dst_id_type),
777 SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
779 SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
782 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
783 return SILC_PACKET_NONE;
786 silc_buffer_push(buffer, len);
788 SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
789 ctx->buffer->data, ctx->buffer->len);
791 /* Pull SILC header and padding from packet */
792 silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
793 ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
795 SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
800 /* Allocate packet context */
802 SilcPacketContext *silc_packet_context_alloc(void)
804 SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
809 /* Increse the reference count of the packet context. */
811 SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
814 SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
819 /* Decrese the reference count of the packet context and free it only if
822 void silc_packet_context_free(SilcPacketContext *ctx)
825 SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
830 silc_buffer_free(ctx->buffer);
832 silc_free(ctx->src_id);
834 silc_free(ctx->dst_id);