/* packet-kink.c * Routines for KINK packet disassembly * It is referenced draft-ietf-kink-kink-jp-04.txt,v 1.14 2003/02/10 * * Copyright 2004, Takeshi Nakashima * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "packet-kerberos.h" #include "packet-isakmp.h" void proto_register_kink(void); void proto_reg_handoff_kink(void); #define KINK_PORT 57203 /* Not IANA registered */ #define KINK_ISAKMP_PAYLOAD_BASE 14 static int proto_kink = -1; /* Argument for proto_tree_add_uint() */ static int hf_kink_type = -1; static int hf_kink_length = -1; static int hf_kink_transactionId = -1; static int hf_kink_checkSumLength = -1; static int hf_kink_A = -1; static int hf_kink_version = -1; static int hf_kink_domain_of_interpretation = -1; static int hf_kink_qmversion = -1; static int hf_kink_error_code = -1; static int hf_kink_reserved8 = -1; static int hf_kink_reserved15 = -1; static int hf_kink_reserved16 = -1; static int hf_kink_reserved24 = -1; static int hf_kink_checkSum = -1; static int hf_kink_next_payload = -1; static int hf_kink_payload_length = -1; static int hf_kink_epoch = -1; static int hf_kink_inner_next_pload = -1; static int hf_kink_realm_name_length = -1; static int hf_kink_realm_name = -1; static int hf_kink_princ_name_length = -1; static int hf_kink_princ_name = -1; static int hf_kink_tgt_length = -1; static int hf_kink_tgt = -1; static int hf_kink_payload = -1; /* Argument for making the subtree */ static gint ett_kink = -1; /*static gint ett_kink_version = -1;*/ static gint ett_kink_payload = -1; static gint ett_payload_kink_ap_req = -1; static gint ett_payload_kink_ap_rep = -1; static gint ett_payload_kink_krb_error = -1; static gint ett_payload_kink_tgt_req = -1; static gint ett_payload_kink_tgt_rep = -1; static gint ett_payload_kink_isakmp = -1; static gint ett_payload_kink_encrypt = -1; static gint ett_payload_kink_error = -1; static gint ett_payload_not_defined = -1; static gint ett_decrypt_kink_encrypt = -1; static expert_field ei_kink_payload_length_small = EI_INIT; static expert_field ei_kink_payload_length_mismatch = EI_INIT; /* Define the kink type value */ #define KINK_TYPE_RESERVED 0 #define KINK_TYPE_CREATE 1 #define KINK_TYPE_DELETE 2 #define KINK_TYPE_REPLY 3 #define KINK_TYPE_GETTGT 4 #define KINK_TYPE_ACK 5 #define KINK_TYPE_STATUS 6 static const value_string kink_type_vals[]={ {KINK_TYPE_RESERVED,"RESERVED"}, {KINK_TYPE_CREATE,"CREATE"}, {KINK_TYPE_DELETE,"DELETE"}, {KINK_TYPE_REPLY,"REPLY"}, {KINK_TYPE_GETTGT,"GETTGT"}, {KINK_TYPE_ACK,"ACK"}, {KINK_TYPE_STATUS,"STATUS"}, {0, NULL}, }; /* Define the kink A value */ #define KINK_A_NOT_REQUEST_ACK 0 #define KINK_A_REQUEST_ACK 1 static const value_string kink_A_vals[]={ {KINK_A_NOT_REQUEST_ACK,"Not Request ACK"}, {KINK_A_REQUEST_ACK,"Request ACK"}, {0, NULL}, }; /* Define the kink payload */ #define KINK_DONE 0 #define KINK_AP_REQ KINK_ISAKMP_PAYLOAD_BASE+0 #define KINK_AP_REP KINK_ISAKMP_PAYLOAD_BASE+1 #define KINK_KRB_ERROR KINK_ISAKMP_PAYLOAD_BASE+2 #define KINK_TGT_REQ KINK_ISAKMP_PAYLOAD_BASE+3 #define KINK_TGT_REP KINK_ISAKMP_PAYLOAD_BASE+4 #define KINK_ISAKMP KINK_ISAKMP_PAYLOAD_BASE+5 #define KINK_ENCRYPT KINK_ISAKMP_PAYLOAD_BASE+6 #define KINK_ERROR KINK_ISAKMP_PAYLOAD_BASE+7 static const value_string kink_next_payload[]={ {KINK_DONE, "KINK_DONE"}, {KINK_AP_REQ, "KINK_AP_REQ"}, {KINK_AP_REP, "KINK_AP_REP"}, {KINK_KRB_ERROR, "KINK_KRB_ERROR"}, {KINK_TGT_REQ, "KINK_TGT_REQ"}, {KINK_TGT_REP, "KINK_TGT_REP"}, {KINK_ISAKMP, "KINK_ISAKMP"}, {KINK_ENCRYPT, "KINK_ENCRYPT"}, {KINK_ERROR, "KINK_ERROR"}, {0, NULL}, }; /* Define the magic number * Using at the kink error */ #define KINK_OK 0 #define KINK_PROTOERR 1 #define KINK_INVDOI 2 #define KINK_INVMAJ 3 #define KINK_INVMIN 4 #define KINK_INTERR 5 #define KINK_BADQMVERS 6 #define BOTTOM_RESERVED 7 #define TOP_RESERVED 8191 #define BOTTOM_PRIVATE_USE 8192 #define TOP_PRIVATE_USE 16383 /* Using at the kink header */ #define IPSEC 1 #define VERSION_BIT_SHIFT 4 #define A_BIT_SHIFT 7 #define FROM_TYPE_TO_RESERVED 16 /* Using at the payload */ #define TO_PAYLOAD_LENGTH 2 #define PADDING 4 #define KINK_KRB_ERROR_HEADER 4 #define FROM_NP_TO_PL 4 #define TO_REALM_NAME_LENGTH 4 #define KINK_TGT_REQ_HEADER 6 #define FRONT_TGT_REP_HEADER 6 #define PAYLOAD_HEADER 8 #define KINK_ERROR_LENGTH 8 /* define hexadecimal */ #define FRONT_FOUR_BIT 0xf0 #define SECOND_FOUR_BIT 0x0f #define FRONT_ONE_BIT 0x80 #define SECOND_FIFTEEN_BIT 0x7fff /* decrypt element */ static guint32 keytype; static void control_payload(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 next_payload, proto_tree *kink_payload_tree); static void dissect_payload_kink_ap_req(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_ap_rep(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_krb_error(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_tgt_req(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_tgt_rep(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_isakmp(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_encrypt(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_error(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); static void dissect_payload_kink_not_defined(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree); #ifdef HAVE_KERBEROS static void dissect_decrypt_kink_encrypt(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree, int payload_length); #endif /* This function is dissecting the kink header. */ static int dissect_kink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_){ proto_item *ti = NULL; proto_tree *kink_tree = NULL; guint8 type; guint32 doi; guint chsumlen; guint8 next_payload; guint8 value_a_and_front_reserved; guint8 value_a; int offset=0; type = tvb_get_guint8(tvb,offset); col_set_str(pinfo->cinfo, COL_PROTOCOL, "KINK"); /* It shows kink type by the type value. */ col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(type, kink_type_vals, "unknown")); /* Make the kink tree */ ti = proto_tree_add_item(tree, proto_kink, tvb, offset, -1, ENC_NA); kink_tree = proto_item_add_subtree(ti, ett_kink); proto_tree_add_uint(kink_tree, hf_kink_type, tvb, offset, 1, type); offset++; proto_tree_add_item(kink_tree, hf_kink_version, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(kink_tree, hf_kink_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; doi = tvb_get_ntohl(tvb, offset); if(doi == IPSEC){ proto_tree_add_uint_format_value(kink_tree, hf_kink_domain_of_interpretation, tvb, offset, 4, doi, "IPsec (%u)", doi); } else{ proto_tree_add_uint_format_value(kink_tree, hf_kink_domain_of_interpretation, tvb, offset, 4, doi, "Not IPsec (%u)", doi); } offset += 4; proto_tree_add_item(kink_tree, hf_kink_transactionId, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; chsumlen = tvb_get_guint8(tvb, offset); proto_tree_add_item(kink_tree, hf_kink_checkSumLength, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(kink_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; /* A is 1bit field. The calculation of A is shown below. * The logical product of 1octet value and 0x80 is performed. * And It is performed 7bit right shift. */ value_a_and_front_reserved = tvb_get_guint8(tvb, offset); value_a = (value_a_and_front_reserved & FRONT_ONE_BIT) >> A_BIT_SHIFT; proto_tree_add_uint(kink_tree, hf_kink_A, tvb, offset, 1, value_a); /* The reserved field is 15bit. * The logical product of 2octet value and 0x7fff is performed. */ proto_tree_add_item(kink_tree, hf_kink_reserved15, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(kink_tree, hf_kink_checkSum, tvb, offset, chsumlen, ENC_NA); /* This part consider the padding. Chsumlen don't contain the padding. */ if((chsumlen % PADDING) != 0){ chsumlen += (PADDING - (chsumlen % PADDING)); offset += chsumlen; } else{ offset += chsumlen; } control_payload(pinfo, tvb, offset, next_payload, kink_tree); return tvb_captured_length(tvb); } /* This part call the dissect payload function by next_payload value. * This function called by the respective function again. */ static void control_payload(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 next_payload, proto_tree *kink_tree){ switch(next_payload){ case KINK_DONE: break; case KINK_AP_REQ: dissect_payload_kink_ap_req(pinfo, tvb, offset, kink_tree); break; case KINK_AP_REP: dissect_payload_kink_ap_rep(pinfo, tvb, offset, kink_tree); break; case KINK_KRB_ERROR: dissect_payload_kink_krb_error(pinfo, tvb, offset, kink_tree); break; case KINK_TGT_REQ: dissect_payload_kink_tgt_req(pinfo, tvb, offset, kink_tree); break; case KINK_TGT_REP: dissect_payload_kink_tgt_rep(pinfo, tvb, offset, kink_tree); break; case KINK_ISAKMP: dissect_payload_kink_isakmp(pinfo, tvb, offset, kink_tree); break; case KINK_ENCRYPT: dissect_payload_kink_encrypt(pinfo, tvb, offset, kink_tree); break; case KINK_ERROR: dissect_payload_kink_error(pinfo, tvb, offset, kink_tree); break; default: dissect_payload_kink_not_defined(pinfo, tvb, offset, kink_tree); break; } } static void dissect_payload_kink_ap_req(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_ap_req_tree; proto_item *ti; guint8 next_payload; guint payload_length; guint16 krb_ap_req_length; int start_payload_offset = 0; /* Keep beginning of payload offset */ start_payload_offset = offset; payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); /* Make the subtree. */ payload_kink_ap_req_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_ap_req, NULL, "KINK_AP_REQ"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_ap_req_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_ap_req_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_ap_req_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length <= PAYLOAD_HEADER){ expert_add_info(pinfo, ti, &ei_kink_payload_length_small); } offset += 2; /* Show time as UTC, not local time. */ proto_tree_add_item(payload_kink_ap_req_tree, hf_kink_epoch, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; if(payload_length > PAYLOAD_HEADER){ tvbuff_t *krb_tvb; krb_ap_req_length = payload_length - PAYLOAD_HEADER; krb_tvb=tvb_new_subset(tvb, offset, (krb_ap_req_length>tvb_captured_length_remaining(tvb, offset))?tvb_captured_length_remaining(tvb, offset):krb_ap_req_length, krb_ap_req_length); keytype=kerberos_output_keytype(); dissect_kerberos_main(krb_tvb, pinfo, payload_kink_ap_req_tree, FALSE, NULL); /*offset += krb_ap_req_length;*/ } /* This part consider padding the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING != 0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } static void dissect_payload_kink_ap_rep(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_ap_rep_tree; proto_item *ti; guint8 next_payload; guint payload_length; guint16 krb_ap_rep_length; int start_payload_offset = 0; /* Keep beginning of payload offset */ payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; /* Make the subtree */ payload_kink_ap_rep_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_ap_rep, NULL, "KINK_AP_REP"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_ap_rep_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_ap_rep_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_ap_rep_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length <= PAYLOAD_HEADER){ expert_add_info(pinfo, ti, &ei_kink_payload_length_small); } offset += 2; /* Show time as UTC, not local time. */ proto_tree_add_item(payload_kink_ap_rep_tree, hf_kink_epoch, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; if(payload_length > PAYLOAD_HEADER){ tvbuff_t *krb_tvb; krb_ap_rep_length = payload_length - PAYLOAD_HEADER; krb_tvb=tvb_new_subset(tvb, offset, (krb_ap_rep_length>tvb_captured_length_remaining(tvb, offset))?tvb_captured_length_remaining(tvb, offset):krb_ap_rep_length, krb_ap_rep_length); keytype=kerberos_output_keytype(); dissect_kerberos_main(krb_tvb, pinfo, payload_kink_ap_rep_tree, FALSE, NULL); /*offset += krb_ap_rep_length;*/ } /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING != 0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } static void dissect_payload_kink_krb_error(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_krb_error_tree; proto_item *ti; guint8 next_payload; guint payload_length; guint16 krb_error_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; /* Make the subtree */ payload_kink_krb_error_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_krb_error, NULL, "KINK_KRB_ERROR"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_krb_error_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_krb_error_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_krb_error_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length <= KINK_KRB_ERROR_HEADER){ expert_add_info(pinfo, ti, &ei_kink_payload_length_small); } else { offset += 2; } if(payload_length > KINK_KRB_ERROR_HEADER){ tvbuff_t *krb_tvb; krb_error_length = payload_length - KINK_KRB_ERROR_HEADER; krb_tvb=tvb_new_subset(tvb, offset, (krb_error_length>tvb_captured_length_remaining(tvb, offset))?tvb_captured_length_remaining(tvb, offset):krb_error_length, krb_error_length); dissect_kerberos_main(krb_tvb, pinfo, payload_kink_krb_error_tree, FALSE, NULL); /*offset += krb_error_length;*/ } /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING != 0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } static void dissect_payload_kink_tgt_req(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_tgt_req_tree; guint8 next_payload; guint payload_length; guint16 realm_name_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); realm_name_length = tvb_get_ntohs(tvb, offset + TO_REALM_NAME_LENGTH); start_payload_offset = offset; /* Make the subtree */ payload_kink_tgt_req_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_tgt_req, NULL, "KINK_TGT_REQ"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_tgt_req_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_tgt_req_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; proto_tree_add_uint(payload_kink_tgt_req_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); offset += 2; proto_tree_add_uint(payload_kink_tgt_req_tree, hf_kink_realm_name_length, tvb, offset, 2, realm_name_length); offset += 2; proto_tree_add_item(payload_kink_tgt_req_tree, hf_kink_realm_name, tvb, offset, realm_name_length, ENC_NA|ENC_ASCII); /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING != 0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } static void dissect_payload_kink_tgt_rep(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_tgt_rep_tree; guint8 next_payload; guint payload_length; guint princ_name_length; guint16 tgt_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; /* Make the subtree */ payload_kink_tgt_rep_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_tgt_rep, NULL, "KINK_TGT_REP"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_tgt_rep_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_tgt_rep_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; proto_tree_add_uint(payload_kink_tgt_rep_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); offset += 2; princ_name_length = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(payload_kink_tgt_rep_tree, hf_kink_princ_name_length, tvb, offset, 2, princ_name_length); offset += 2; proto_tree_add_item(payload_kink_tgt_rep_tree, hf_kink_princ_name, tvb, offset, princ_name_length, ENC_NA|ENC_ASCII); /* This part consider the padding. Princ_name_length don't contain the padding. */ if((princ_name_length + FRONT_TGT_REP_HEADER) % PADDING != 0){ offset += (princ_name_length + PADDING - ((princ_name_length + FRONT_TGT_REP_HEADER) % PADDING)); } else{ offset += princ_name_length; } tgt_length = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(payload_kink_tgt_rep_tree, hf_kink_tgt_length, tvb, offset, 2, tgt_length); offset += 2; proto_tree_add_item(payload_kink_tgt_rep_tree, hf_kink_tgt, tvb, offset, tgt_length, ENC_NA|ENC_ASCII); /*offset += tgt_length;*/ /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING!=0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } static void dissect_payload_kink_isakmp(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_isakmp_tree; proto_item *ti; guint8 next_payload; guint payload_length,isakmp_length; int length, reported_length; guint8 inner_next_pload; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ tvbuff_t *isakmp_tvb; payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; /* Make the subtree. */ payload_kink_isakmp_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_isakmp, NULL, "KINK_ISAKMP"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_isakmp_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_isakmp_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_isakmp_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length <= PAYLOAD_HEADER){ expert_add_info(pinfo, ti, &ei_kink_payload_length_small); } offset += 2; inner_next_pload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_isakmp_tree, hf_kink_inner_next_pload, tvb, offset, 1, inner_next_pload); offset += 1; proto_tree_add_item(payload_kink_isakmp_tree, hf_kink_qmversion, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(payload_kink_isakmp_tree, hf_kink_reserved16, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; if(payload_length > PAYLOAD_HEADER){ isakmp_length = payload_length - PAYLOAD_HEADER; length = tvb_captured_length_remaining(tvb, offset); if (length > (int)isakmp_length) length = isakmp_length; reported_length = tvb_reported_length_remaining(tvb, offset); if (reported_length > (int)isakmp_length) reported_length = isakmp_length; isakmp_tvb = tvb_new_subset(tvb, offset, length, reported_length); isakmp_dissect_payloads(isakmp_tvb, payload_kink_isakmp_tree, 1, inner_next_pload, 0, isakmp_length, pinfo); } /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING != 0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } static void dissect_payload_kink_encrypt(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_encrypt_tree; proto_item *ti; guint8 next_payload; guint payload_length; #ifdef HAVE_KERBEROS gint encrypt_length; #endif guint8 inner_next_pload; guint16 inner_payload_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ payload_length = tvb_get_ntohs(tvb,offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; #ifdef HAVE_KERBEROS encrypt_length = payload_length - FROM_NP_TO_PL; #endif /* Make the subtree */ payload_kink_encrypt_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_encrypt, NULL, "KINK_ENCRYPT"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_encrypt_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length <= PAYLOAD_HEADER){ expert_add_info(pinfo, ti, &ei_kink_payload_length_small); } offset += 2; /* decrypt kink encrypt */ if(keytype != 0){ #ifdef HAVE_KERBEROS tvbuff_t *next_tvb; guint8 *plaintext=NULL; next_tvb=tvb_new_subset(tvb, offset, MIN(tvb_captured_length_remaining(tvb, offset), encrypt_length), encrypt_length); plaintext=decrypt_krb5_data(tree, pinfo, 0, next_tvb, keytype, NULL); if(plaintext){ next_tvb=tvb_new_child_real_data(tvb, plaintext, encrypt_length, encrypt_length); add_new_data_source(pinfo, next_tvb, "decrypted kink encrypt"); dissect_decrypt_kink_encrypt(pinfo, next_tvb, tree, encrypt_length); } #endif } else{ inner_next_pload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_inner_next_pload, tvb, offset, 1, inner_next_pload); offset += 1; proto_tree_add_item(payload_kink_encrypt_tree, hf_kink_reserved24, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; if(payload_length > PAYLOAD_HEADER){ inner_payload_length = payload_length - PAYLOAD_HEADER; proto_tree_add_item(payload_kink_encrypt_tree, hf_kink_payload, tvb, offset, inner_payload_length, ENC_NA); /*offset += inner_payload_length;*/ } } /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING !=0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } } #ifdef HAVE_KERBEROS static void dissect_decrypt_kink_encrypt(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree, int payload_length){ proto_tree *decrypt_kink_encrypt_tree; int offset=0; guint8 next_payload; decrypt_kink_encrypt_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_decrypt_kink_encrypt, NULL, "decrypted data"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(decrypt_kink_encrypt_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(decrypt_kink_encrypt_tree, hf_kink_reserved24, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; control_payload(pinfo, tvb, offset, next_payload, decrypt_kink_encrypt_tree); } #endif static const range_string kink_error_rvals[] = { { 0, 0, "KINK_OK" }, { 1, 1, "KINK_PROTOERR" }, { 2, 2, "KINK_INVDOI" }, { 3, 3, "KINK_INVMAJ" }, { 4, 4, "KINK_INVMIN" }, { 5, 5, "KINK_INTERR" }, { 6, 6, "KINK_BADQMVERS" }, { BOTTOM_RESERVED, TOP_RESERVED, "RESERVED" }, { BOTTOM_PRIVATE_USE, TOP_PRIVATE_USE, "PRIVATE USE" }, { TOP_PRIVATE_USE+1, 0xffffffff, "This Error Code is not Defined." }, { 0, 0, NULL } }; static void dissect_payload_kink_error(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_error_tree; proto_item *ti; guint8 next_payload; guint16 payload_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ payload_length = tvb_get_ntohs(tvb,offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; /* Make the subtree */ payload_kink_error_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_kink_error, NULL, "KINK_ERROR"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_error_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_error_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_error_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length != KINK_ERROR_LENGTH){ expert_add_info(pinfo, ti, &ei_kink_payload_length_mismatch); } offset += 2; proto_tree_add_item(payload_kink_error_tree, hf_kink_error_code, tvb, offset, 4, ENC_BIG_ENDIAN); offset = start_payload_offset + KINK_ERROR_LENGTH; control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } static void dissect_payload_kink_not_defined(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_not_defined_tree; guint8 next_payload; guint payload_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ start_payload_offset = offset; payload_length = tvb_get_ntohs(tvb, offset + TO_PAYLOAD_LENGTH); /* Make the subtree */ payload_kink_not_defined_tree = proto_tree_add_subtree(tree, tvb, offset, payload_length, ett_payload_not_defined, NULL, "UNKNOWN PAYLOAD"); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_not_defined_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_not_defined_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; proto_tree_add_uint(payload_kink_not_defined_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING != 0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; /* XXX - prevent an endless loop if payload_length is 0, don't know the correct way to handle this! */ if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); } } static void kink_fmt_version( gchar *result, guint32 version ) { guint8 major_version, minor_version; /* This part is the version. Consider less than 1 octet value. * Major version and minor version is 4bit. Front half of 1octet * is major version, and second half of 1octet is minor version. * The calculation of major version is shown below. * The logical product of the value of 1octet and 0xf0 is performed. * And It is performed 4bit right shift. * Secondarily, the calculation of minor version is shown below. * The logical product of the value of 1octet and 0x0f is performed. */ major_version = (guint8)((version & FRONT_FOUR_BIT) >> VERSION_BIT_SHIFT); minor_version = (guint8)(version & SECOND_FOUR_BIT); g_snprintf( result, ITEM_LABEL_LENGTH, "%d.%02d", major_version, minor_version); } /* Output part */ void proto_register_kink(void) { static hf_register_info hf[] = { { &hf_kink_type, { "Type", "kink.type", FT_UINT8, BASE_DEC, VALS(kink_type_vals), 0x0, NULL, HFILL }}, { &hf_kink_length, { "Length", "kink.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_transactionId, { "Transaction ID", "kink.transactionId", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_checkSumLength, { "Checksum Length", "kink.checkSumLength", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_A, { "A", "kink.A", FT_UINT8, BASE_DEC, VALS(kink_A_vals), 0x0, NULL, HFILL }}, { &hf_kink_version, { "Version", "kink.version", FT_UINT8, BASE_CUSTOM, CF_FUNC(kink_fmt_version), 0x0, NULL, HFILL }}, { &hf_kink_domain_of_interpretation, { "Domain Of Interpretation", "kink.domain_of_interpretation", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_qmversion, { "QMVersion", "kink.qmversion", FT_UINT8, BASE_CUSTOM, CF_FUNC(kink_fmt_version), 0x0, NULL, HFILL }}, { &hf_kink_error_code, { "ErrorCode", "kink.error_code", FT_UINT32, BASE_DEC|BASE_RANGE_STRING, RVALS(kink_error_rvals), 0x0, NULL, HFILL }}, { &hf_kink_reserved8, { "Reserved", "kink.reserved", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_reserved15, { "Reserved", "kink.reserved", FT_UINT16, BASE_DEC, NULL, SECOND_FIFTEEN_BIT, NULL, HFILL }}, { &hf_kink_reserved16, { "Reserved", "kink.reserved", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_kink_reserved24, { "Reserved", "kink.reserved", FT_UINT24, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_kink_checkSum, { "Checksum", "kink.checkSum", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_kink_next_payload, { "Next Payload", "kink.nextPayload", FT_UINT8, BASE_DEC, VALS(kink_next_payload), 0x0, NULL, HFILL }}, { &hf_kink_payload_length, { "Payload Length", "kink.payloadLength", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_epoch, { "EPOCH", "kink.epoch", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_inner_next_pload, { "InnerNextPload", "kink.innerNextPload", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_kink_realm_name_length, { "RealmNameLength", "kink.realmNameLength", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_kink_realm_name, { "RealmName", "kink.realmName", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }}, { &hf_kink_princ_name_length, { "PrincNameLength", "kink.princNameLength", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_kink_princ_name, { "PrincName", "kink.princName", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }}, { &hf_kink_tgt_length, { "TGT Length", "kink.tgtLength", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_kink_tgt, { "TGT", "kink.tgt", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }}, { &hf_kink_payload, { "Payload", "kink.payload", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, }; /* Argument for making the subtree. */ static gint *ett[] = { &ett_kink, /* &ett_kink_version, */ &ett_kink_payload, &ett_payload_kink_ap_req, &ett_payload_kink_ap_rep, &ett_payload_kink_krb_error, &ett_payload_kink_tgt_req, &ett_payload_kink_tgt_rep, &ett_payload_kink_isakmp, &ett_payload_kink_encrypt, &ett_payload_kink_error, &ett_payload_not_defined, &ett_decrypt_kink_encrypt, }; static ei_register_info ei[] = { { &ei_kink_payload_length_small, { "kink.payload_length_small", PI_PROTOCOL, PI_WARN, "This Payload Length is too small", EXPFILL }}, { &ei_kink_payload_length_mismatch, { "kink.payload_length_mismatch", PI_PROTOCOL, PI_WARN, "This Payload Length is mismatch", EXPFILL }}, }; expert_module_t* expert_kink; proto_kink = proto_register_protocol("Kerberized Internet Negotiation of Key", "KINK", "kink"); proto_register_field_array(proto_kink, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_kink = expert_register_protocol(proto_kink); expert_register_field_array(expert_kink, ei, array_length(ei)); } void proto_reg_handoff_kink(void) { dissector_handle_t kink_handle; kink_handle = create_dissector_handle(dissect_kink, proto_kink); dissector_add_uint_with_preference("udp.port", KINK_PORT, kink_handle); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local Variables: * c-basic-offset: 2 * tab-width: 8 * indent-tabs-mode: nil * End: * * ex: set shiftwidth=2 tabstop=8 expandtab: * :indentSize=2:tabSize=8:noTabs=true: */