X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/69cb46af9119e8b5554bcc4bf1bf36f39cb82131..d7b497cac78b6e22a66a6bae9bdec60a8044f67a:/print-l2tp.c diff --git a/print-l2tp.c b/print-l2tp.c index 514eb2c5..6cf0c0ad 100644 --- a/print-l2tp.c +++ b/print-l2tp.c @@ -21,13 +21,15 @@ * L2TP support contributed by Motonori Shindo (mshindo@mshindo.net) */ +/* \summary: Layer Two Tunneling Protocol (L2TP) printer */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include +#include -#include "interface.h" +#include "netdissect.h" #include "extract.h" #define L2TP_FLAG_TYPE 0x8000 /* Type (0=Data, 1=Control) */ @@ -266,7 +268,8 @@ print_string(netdissect_options *ndo, const u_char *dat, u_int length) { u_int i; for (i=0; i 2) { /* Error Code (opt) */ - ND_PRINT((ndo, "/%u", EXTRACT_16BITS(ptr))); ptr++; + /* Result Code */ + if (length < 2) { + ND_PRINT((ndo, "AVP too short")); + return; } - if (length > 4) { /* Error Message (opt) */ - ND_PRINT((ndo, " ")); - print_string(ndo, (const u_char *)ptr, length - 4); + ND_PRINT((ndo, "%u", EXTRACT_BE_U_2(ptr))); + ptr++; + length -= 2; + + /* Error Code (opt) */ + if (length == 0) + return; + if (length < 2) { + ND_PRINT((ndo, " AVP too short")); + return; } + ND_PRINT((ndo, "/%u", EXTRACT_BE_U_2(ptr))); + ptr++; + length -= 2; + + /* Error Message (opt) */ + if (length == 0) + return; + ND_PRINT((ndo, " ")); + print_string(ndo, (const u_char *)ptr, length); } static void -l2tp_proto_ver_print(netdissect_options *ndo, const uint16_t *dat) +l2tp_proto_ver_print(netdissect_options *ndo, const uint16_t *dat, u_int length) { - ND_PRINT((ndo, "%u.%u", (EXTRACT_16BITS(dat) >> 8), - (EXTRACT_16BITS(dat) & 0xff))); + if (length < 2) { + ND_PRINT((ndo, "AVP too short")); + return; + } + ND_PRINT((ndo, "%u.%u", (EXTRACT_BE_U_2(dat) >> 8), + (EXTRACT_BE_U_2(dat) & 0xff))); } static void -l2tp_framing_cap_print(netdissect_options *ndo, const u_char *dat) +l2tp_framing_cap_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint32_t *ptr = (const uint32_t *)dat; - if (EXTRACT_32BITS(ptr) & L2TP_FRAMING_CAP_ASYNC_MASK) { + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + if (EXTRACT_BE_U_4(ptr) & L2TP_FRAMING_CAP_ASYNC_MASK) { ND_PRINT((ndo, "A")); } - if (EXTRACT_32BITS(ptr) & L2TP_FRAMING_CAP_SYNC_MASK) { + if (EXTRACT_BE_U_4(ptr) & L2TP_FRAMING_CAP_SYNC_MASK) { ND_PRINT((ndo, "S")); } } static void -l2tp_bearer_cap_print(netdissect_options *ndo, const u_char *dat) +l2tp_bearer_cap_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint32_t *ptr = (const uint32_t *)dat; - if (EXTRACT_32BITS(ptr) & L2TP_BEARER_CAP_ANALOG_MASK) { + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + if (EXTRACT_BE_U_4(ptr) & L2TP_BEARER_CAP_ANALOG_MASK) { ND_PRINT((ndo, "A")); } - if (EXTRACT_32BITS(ptr) & L2TP_BEARER_CAP_DIGITAL_MASK) { + if (EXTRACT_BE_U_4(ptr) & L2TP_BEARER_CAP_DIGITAL_MASK) { ND_PRINT((ndo, "D")); } } @@ -354,36 +391,50 @@ l2tp_bearer_cap_print(netdissect_options *ndo, const u_char *dat) static void l2tp_q931_cc_print(netdissect_options *ndo, const u_char *dat, u_int length) { + if (length < 3) { + ND_PRINT((ndo, "AVP too short")); + return; + } print_16bits_val(ndo, (const uint16_t *)dat); - ND_PRINT((ndo, ", %02x", dat[2])); - if (length > 3) { + ND_PRINT((ndo, ", %02x", EXTRACT_U_1(dat + 2))); + dat += 3; + length -= 3; + if (length != 0) { ND_PRINT((ndo, " ")); - print_string(ndo, dat+3, length-3); + print_string(ndo, dat, length); } } static void -l2tp_bearer_type_print(netdissect_options *ndo, const u_char *dat) +l2tp_bearer_type_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint32_t *ptr = (const uint32_t *)dat; - if (EXTRACT_32BITS(ptr) & L2TP_BEARER_TYPE_ANALOG_MASK) { + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + if (EXTRACT_BE_U_4(ptr) & L2TP_BEARER_TYPE_ANALOG_MASK) { ND_PRINT((ndo, "A")); } - if (EXTRACT_32BITS(ptr) & L2TP_BEARER_TYPE_DIGITAL_MASK) { + if (EXTRACT_BE_U_4(ptr) & L2TP_BEARER_TYPE_DIGITAL_MASK) { ND_PRINT((ndo, "D")); } } static void -l2tp_framing_type_print(netdissect_options *ndo, const u_char *dat) +l2tp_framing_type_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint32_t *ptr = (const uint32_t *)dat; - if (EXTRACT_32BITS(ptr) & L2TP_FRAMING_TYPE_ASYNC_MASK) { + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + if (EXTRACT_BE_U_4(ptr) & L2TP_FRAMING_TYPE_ASYNC_MASK) { ND_PRINT((ndo, "A")); } - if (EXTRACT_32BITS(ptr) & L2TP_FRAMING_TYPE_SYNC_MASK) { + if (EXTRACT_BE_U_4(ptr) & L2TP_FRAMING_TYPE_SYNC_MASK) { ND_PRINT((ndo, "S")); } } @@ -395,69 +446,119 @@ l2tp_packet_proc_delay_print(netdissect_options *ndo) } static void -l2tp_proxy_auth_type_print(netdissect_options *ndo, const u_char *dat) +l2tp_proxy_auth_type_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint16_t *ptr = (const uint16_t *)dat; + if (length < 2) { + ND_PRINT((ndo, "AVP too short")); + return; + } ND_PRINT((ndo, "%s", tok2str(l2tp_authentype2str, - "AuthType-#%u", EXTRACT_16BITS(ptr)))); + "AuthType-#%u", EXTRACT_BE_U_2(ptr)))); } static void -l2tp_proxy_auth_id_print(netdissect_options *ndo, const u_char *dat) +l2tp_proxy_auth_id_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint16_t *ptr = (const uint16_t *)dat; - ND_PRINT((ndo, "%u", EXTRACT_16BITS(ptr) & L2TP_PROXY_AUTH_ID_MASK)); + if (length < 2) { + ND_PRINT((ndo, "AVP too short")); + return; + } + ND_PRINT((ndo, "%u", EXTRACT_BE_U_2(ptr) & L2TP_PROXY_AUTH_ID_MASK)); } static void -l2tp_call_errors_print(netdissect_options *ndo, const u_char *dat) +l2tp_call_errors_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint16_t *ptr = (const uint16_t *)dat; uint16_t val_h, val_l; + if (length < 2) { + ND_PRINT((ndo, "AVP too short")); + return; + } ptr++; /* skip "Reserved" */ + length -= 2; - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; + val_l = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; ND_PRINT((ndo, "CRCErr=%u ", (val_h<<16) + val_l)); - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; + val_l = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; ND_PRINT((ndo, "FrameErr=%u ", (val_h<<16) + val_l)); - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; + val_l = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; ND_PRINT((ndo, "HardOver=%u ", (val_h<<16) + val_l)); - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; + val_l = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; ND_PRINT((ndo, "BufOver=%u ", (val_h<<16) + val_l)); - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; + val_l = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; ND_PRINT((ndo, "Timeout=%u ", (val_h<<16) + val_l)); - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; + val_l = EXTRACT_BE_U_2(ptr); ptr++; ND_PRINT((ndo, "AlignErr=%u ", (val_h<<16) + val_l)); } static void -l2tp_accm_print(netdissect_options *ndo, const u_char *dat) +l2tp_accm_print(netdissect_options *ndo, const u_char *dat, u_int length) { const uint16_t *ptr = (const uint16_t *)dat; uint16_t val_h, val_l; + if (length < 2) { + ND_PRINT((ndo, "AVP too short")); + return; + } ptr++; /* skip "Reserved" */ + length -= 2; - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; + val_l = EXTRACT_BE_U_2(ptr); ptr++; length -= 2; ND_PRINT((ndo, "send=%08x ", (val_h<<16) + val_l)); - val_h = EXTRACT_16BITS(ptr); ptr++; - val_l = EXTRACT_16BITS(ptr); ptr++; + if (length < 4) { + ND_PRINT((ndo, "AVP too short")); + return; + } + val_h = EXTRACT_BE_U_2(ptr); ptr++; + val_l = EXTRACT_BE_U_2(ptr); ptr++; ND_PRINT((ndo, "recv=%08x ", (val_h<<16) + val_l)); } @@ -466,14 +567,27 @@ l2tp_ppp_discon_cc_print(netdissect_options *ndo, const u_char *dat, u_int lengt { const uint16_t *ptr = (const uint16_t *)dat; - ND_PRINT((ndo, "%04x, ", EXTRACT_16BITS(ptr))); ptr++; /* Disconnect Code */ - ND_PRINT((ndo, "%04x ", EXTRACT_16BITS(ptr))); ptr++; /* Control Protocol Number */ + if (length < 5) { + ND_PRINT((ndo, "AVP too short")); + return; + } + /* Disconnect Code */ + ND_PRINT((ndo, "%04x, ", EXTRACT_BE_U_2(dat))); + dat += 2; + length -= 2; + /* Control Protocol Number */ + ND_PRINT((ndo, "%04x ", EXTRACT_BE_U_2(dat))); + dat += 2; + length -= 2; + /* Direction */ ND_PRINT((ndo, "%s", tok2str(l2tp_cc_direction2str, - "Direction-#%u", *((const u_char *)ptr++)))); + "Direction-#%u", EXTRACT_U_1(ptr)))); + ptr++; + length--; - if (length > 5) { + if (length != 0) { ND_PRINT((ndo, " ")); - print_string(ndo, (const u_char *)ptr, length-5); + print_string(ndo, (const u_char *)ptr, length); } } @@ -492,7 +606,7 @@ l2tp_avp_print(netdissect_options *ndo, const u_char *dat, int length) ND_PRINT((ndo, " ")); ND_TCHECK(*ptr); /* Flags & Length */ - len = EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_LEN_MASK; + len = EXTRACT_BE_U_2(ptr) & L2TP_AVP_HDR_LEN_MASK; /* If it is not long enough to contain the header, we'll give up. */ if (len < 6) @@ -506,28 +620,33 @@ l2tp_avp_print(netdissect_options *ndo, const u_char *dat, int length) /* If it goes past the end of the remaining length of the captured data, we'll give up. */ ND_TCHECK2(*ptr, len); - /* After this point, no need to worry about truncation */ - if (EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_FLAG_MANDATORY) { + /* + * After this point, we don't need to check whether we go past + * the length of the captured data; however, we *do* need to + * check whether we go past the end of the AVP. + */ + + if (EXTRACT_BE_U_2(ptr) & L2TP_AVP_HDR_FLAG_MANDATORY) { ND_PRINT((ndo, "*")); } - if (EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_FLAG_HIDDEN) { + if (EXTRACT_BE_U_2(ptr) & L2TP_AVP_HDR_FLAG_HIDDEN) { hidden = TRUE; ND_PRINT((ndo, "?")); } ptr++; - if (EXTRACT_16BITS(ptr)) { + if (EXTRACT_BE_U_2(ptr)) { /* Vendor Specific Attribute */ - ND_PRINT((ndo, "VENDOR%04x:", EXTRACT_16BITS(ptr))); ptr++; - ND_PRINT((ndo, "ATTR%04x", EXTRACT_16BITS(ptr))); ptr++; + ND_PRINT((ndo, "VENDOR%04x:", EXTRACT_BE_U_2(ptr))); ptr++; + ND_PRINT((ndo, "ATTR%04x", EXTRACT_BE_U_2(ptr))); ptr++; ND_PRINT((ndo, "(")); print_octets(ndo, (const u_char *)ptr, len-6); ND_PRINT((ndo, ")")); } else { /* IETF-defined Attributes */ ptr++; - attr_type = EXTRACT_16BITS(ptr); ptr++; + attr_type = EXTRACT_BE_U_2(ptr); ptr++; ND_PRINT((ndo, "%s", tok2str(l2tp_avp2str, "AVP-#%u", attr_type))); ND_PRINT((ndo, "(")); if (hidden) { @@ -535,27 +654,35 @@ l2tp_avp_print(netdissect_options *ndo, const u_char *dat, int length) } else { switch (attr_type) { case L2TP_AVP_MSGTYPE: - l2tp_msgtype_print(ndo, (const u_char *)ptr); + l2tp_msgtype_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_RESULT_CODE: l2tp_result_code_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_PROTO_VER: - l2tp_proto_ver_print(ndo, ptr); + l2tp_proto_ver_print(ndo, ptr, len-6); break; case L2TP_AVP_FRAMING_CAP: - l2tp_framing_cap_print(ndo, (const u_char *)ptr); + l2tp_framing_cap_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_BEARER_CAP: - l2tp_bearer_cap_print(ndo, (const u_char *)ptr); + l2tp_bearer_cap_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_TIE_BREAKER: + if (len-6 < 8) { + ND_PRINT((ndo, "AVP too short")); + break; + } print_octets(ndo, (const u_char *)ptr, 8); break; case L2TP_AVP_FIRM_VER: case L2TP_AVP_ASSND_TUN_ID: case L2TP_AVP_RECV_WIN_SIZE: case L2TP_AVP_ASSND_SESS_ID: + if (len-6 < 2) { + ND_PRINT((ndo, "AVP too short")); + break; + } print_16bits_val(ndo, ptr); break; case L2TP_AVP_HOST_NAME: @@ -580,6 +707,10 @@ l2tp_avp_print(netdissect_options *ndo, const u_char *dat, int length) l2tp_q931_cc_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_CHALLENGE_RESP: + if (len-6 < 16) { + ND_PRINT((ndo, "AVP too short")); + break; + } print_octets(ndo, (const u_char *)ptr, 16); break; case L2TP_AVP_CALL_SER_NUM: @@ -588,28 +719,32 @@ l2tp_avp_print(netdissect_options *ndo, const u_char *dat, int length) case L2TP_AVP_TX_CONN_SPEED: case L2TP_AVP_PHY_CHANNEL_ID: case L2TP_AVP_RX_CONN_SPEED: + if (len-6 < 4) { + ND_PRINT((ndo, "AVP too short")); + break; + } print_32bits_val(ndo, (const uint32_t *)ptr); break; case L2TP_AVP_BEARER_TYPE: - l2tp_bearer_type_print(ndo, (const u_char *)ptr); + l2tp_bearer_type_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_FRAMING_TYPE: - l2tp_framing_type_print(ndo, (const u_char *)ptr); + l2tp_framing_type_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_PACKET_PROC_DELAY: l2tp_packet_proc_delay_print(ndo); break; case L2TP_AVP_PROXY_AUTH_TYPE: - l2tp_proxy_auth_type_print(ndo, (const u_char *)ptr); + l2tp_proxy_auth_type_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_PROXY_AUTH_ID: - l2tp_proxy_auth_id_print(ndo, (const u_char *)ptr); + l2tp_proxy_auth_id_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_CALL_ERRORS: - l2tp_call_errors_print(ndo, (const u_char *)ptr); + l2tp_call_errors_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_ACCM: - l2tp_accm_print(ndo, (const u_char *)ptr); + l2tp_accm_print(ndo, (const u_char *)ptr, len-6); break; case L2TP_AVP_SEQ_REQUIRED: break; /* No Attribute Value */ @@ -642,10 +777,10 @@ l2tp_print(netdissect_options *ndo, const u_char *dat, u_int length) flag_t = flag_l = flag_s = flag_o = FALSE; - ND_TCHECK2(*ptr, 2); /* Flags & Version */ - if ((EXTRACT_16BITS(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2TP) { + ND_TCHECK_2(ptr); /* Flags & Version */ + if ((EXTRACT_BE_U_2(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2TP) { ND_PRINT((ndo, " l2tp:")); - } else if ((EXTRACT_16BITS(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2F) { + } else if ((EXTRACT_BE_U_2(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2F) { ND_PRINT((ndo, " l2f:")); return; /* nothing to do */ } else { @@ -654,23 +789,23 @@ l2tp_print(netdissect_options *ndo, const u_char *dat, u_int length) } ND_PRINT((ndo, "[")); - if (EXTRACT_16BITS(ptr) & L2TP_FLAG_TYPE) { + if (EXTRACT_BE_U_2(ptr) & L2TP_FLAG_TYPE) { flag_t = TRUE; ND_PRINT((ndo, "T")); } - if (EXTRACT_16BITS(ptr) & L2TP_FLAG_LENGTH) { + if (EXTRACT_BE_U_2(ptr) & L2TP_FLAG_LENGTH) { flag_l = TRUE; ND_PRINT((ndo, "L")); } - if (EXTRACT_16BITS(ptr) & L2TP_FLAG_SEQUENCE) { + if (EXTRACT_BE_U_2(ptr) & L2TP_FLAG_SEQUENCE) { flag_s = TRUE; ND_PRINT((ndo, "S")); } - if (EXTRACT_16BITS(ptr) & L2TP_FLAG_OFFSET) { + if (EXTRACT_BE_U_2(ptr) & L2TP_FLAG_OFFSET) { flag_o = TRUE; ND_PRINT((ndo, "O")); } - if (EXTRACT_16BITS(ptr) & L2TP_FLAG_PRIORITY) + if (EXTRACT_BE_U_2(ptr) & L2TP_FLAG_PRIORITY) ND_PRINT((ndo, "P")); ND_PRINT((ndo, "]")); @@ -678,37 +813,37 @@ l2tp_print(netdissect_options *ndo, const u_char *dat, u_int length) cnt += 2; if (flag_l) { - ND_TCHECK2(*ptr, 2); /* Length */ - l2tp_len = EXTRACT_16BITS(ptr); + ND_TCHECK_2(ptr); /* Length */ + l2tp_len = EXTRACT_BE_U_2(ptr); ptr += 2; cnt += 2; } else { l2tp_len = 0; } - ND_TCHECK2(*ptr, 2); /* Tunnel ID */ - ND_PRINT((ndo, "(%u/", EXTRACT_16BITS(ptr))); + ND_TCHECK_2(ptr); /* Tunnel ID */ + ND_PRINT((ndo, "(%u/", EXTRACT_BE_U_2(ptr))); ptr += 2; cnt += 2; - ND_TCHECK2(*ptr, 2); /* Session ID */ - ND_PRINT((ndo, "%u)", EXTRACT_16BITS(ptr))); + ND_TCHECK_2(ptr); /* Session ID */ + ND_PRINT((ndo, "%u)", EXTRACT_BE_U_2(ptr))); ptr += 2; cnt += 2; if (flag_s) { - ND_TCHECK2(*ptr, 2); /* Ns */ - ND_PRINT((ndo, "Ns=%u,", EXTRACT_16BITS(ptr))); + ND_TCHECK_2(ptr); /* Ns */ + ND_PRINT((ndo, "Ns=%u,", EXTRACT_BE_U_2(ptr))); ptr += 2; cnt += 2; - ND_TCHECK2(*ptr, 2); /* Nr */ - ND_PRINT((ndo, "Nr=%u", EXTRACT_16BITS(ptr))); + ND_TCHECK_2(ptr); /* Nr */ + ND_PRINT((ndo, "Nr=%u", EXTRACT_BE_U_2(ptr))); ptr += 2; cnt += 2; } if (flag_o) { - ND_TCHECK2(*ptr, 2); /* Offset Size */ - pad = EXTRACT_16BITS(ptr); + ND_TCHECK_2(ptr); /* Offset Size */ + pad = EXTRACT_BE_U_2(ptr); ptr += (2 + pad); cnt += (2 + pad); }