#include #include "main.h" #include "l2tp.h" #include "util.h" #include "vars.h" #define HDR_F_T 0x8000 #define HDR_F_L 0x4000 #define HDR_F_S 0x0800 #define HDR_F_O 0x0200 #define HDR_F_P 0x0100 #define HDR_F_VER_SHIFT 0 #define HDR_F_VER_MASK 15 #define HDR_F_MBZ 0x34f0 #define AVP_F_M 0x8000 #define AVP_F_H 0x4000 #define AVP_F_LEN_SHIFT 0 #define AVP_F_LEN_MASK 0x03ff #define AVP_F_MBZ 0x3c00 #define VFOP_PTYPE 1 #define VFOP_VALUE 2 static int have_msgtype; static unsigned int msgtype; #define MSGTYPE_IS(n) (have_msgtype && (msgtype == (n))) static void val_message_type(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Message Type]"); break; case VFOP_VALUE: printx(pkt,len); if (len == 2) { unsigned int t; t = get16(0); printf(" Type [%u",t); switch (t) { case 1: printf("=SCCRQ"); break; case 2: printf("=SCCRP"); break; case 3: printf("=SCCCN"); break; case 4: printf("=StopCCN"); break; case 6: printf("=HELLO"); break; case 7: printf("=OCRQ"); break; case 8: printf("=OCRP"); break; case 9: printf("=OCCN"); break; case 10: printf("=ICRQ"); break; case 11: printf("=ICRP"); break; case 12: printf("=ICCN"); break; case 14: printf("=CDN"); break; case 15: printf("=WEN"); break; case 16: printf("=SLI"); break; } printf("]\n"); if (have_msgtype) { printx(pkt,0); printf("*** Multiple Mssage Type AVPs\n"); } have_msgtype = 1; msgtype = t; } else { printf(" Value (length wrong)\n"); } break; } } static void val_result_code(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Result Code]"); break; case VFOP_VALUE: switch (len) { unsigned int rc; unsigned int ec; case 0: case 1: case 3: printx(pkt,len); printf(" Value (length wrong)\n"); break; default: rc = get16(0); printx(pkt,2); printf(" Result Code [%u",rc); if (MSGTYPE_IS(4)) { switch (rc) { case 1: printf(": General request to clear control connection"); break; case 2: printf(": General error - see Error Code"); break; case 3: printf(": Control channel already exists"); break; case 4: printf(": Not authorized to establish a control channel"); break; case 5: printf(": Protocol version not supported"); break; case 6: printf(": Being shut down"); break; case 7: printf(": FSM error"); break; } } else if (MSGTYPE_IS(14)) { switch (rc) { case 1: printf(": Disconnected, loss of carrier"); break; case 2: printf(": Disconnected, see Error Code"); break; case 3: printf(": Disconnected, administrative reasons"); break; case 4: printf(": Failed, facilities unavailable (temporary)"); break; case 5: printf(": Failed, facilities unavailable (permanent)"); break; case 6: printf(": Invalid destination"); break; case 7: printf(": Failed, no carrier"); break; case 8: printf(": Failed, busy"); break; case 9: printf(": Failed, no dialtone"); break; case 10: printf(": Failed, timeout"); break; case 11: printf(": Failed, no appropriate framing"); break; } } printf("]\n"); if (len > 2) { ec = get16(2); printx(pkt+2,2); printf(" Error Code [%u",ec); switch (ec) { case 0: printf(": No error"); break; case 1: printf(": No control connection yet"); break; case 2: printf(": Length wrong"); break; case 3: printf(": Invalid/reserved value"); break; case 4: printf(": Resource shortage"); break; case 5: printf(": Invalid Session ID"); break; case 6: printf(": Generic vendor-specific error"); break; case 7: printf(": Try another"); break; case 8: printf(": Unknown mandatory AVP"); break; } printf("]\n"); } if (len > 4) { printxu(pkt+4,len-4); printf(" Error Message\n"); } break; } break; } } static void val_protocol_version(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Protocol Version]"); break; case VFOP_VALUE: if (len == 2) { unsigned int v; unsigned int r; printx(pkt,2); v = get8(0); r = get8(1); printf(" Ver %u, rev %u\n",v,r); if ((v != 1) || (r != 0)) { printx(pkt,0); printf("*** Should be ver 1, rev 0\n"); } } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_framing_capabilities(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Framing Capabilities]"); break; case VFOP_VALUE: if (len == 4) { unsigned int cap; cap = get32(0); printx(pkt,4); printf(" S=%d A=%d",cap&1,(cap>>1)&1); if (cap & ~3U) printf(" (reserved %08x)",cap&~3U); printf("\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_bearer_capabilities(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Bearer Capabilities]"); break; case VFOP_VALUE: if (len == 4) { unsigned int cap; cap = get32(0); printx(pkt,4); printf(" D=%d A=%d",cap&1,(cap>>1)&1); if (cap & ~3U) printf(" (reserved %08x)",cap&~3U); printf("\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_tie_breaker(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Tie Breaker]"); break; case VFOP_VALUE: if (len == 8) { printx(pkt,8); printf(" Tie break value\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_firmware_revision(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Firmware Revision]"); break; case VFOP_VALUE: if (len == 2) { unsigned int rev; printx(pkt,2); rev = get16(0); printf(" FW Rev %u\n",rev); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_host_name(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Host Name]"); break; case VFOP_VALUE: if (len > 0) { printxu(pkt,len); printf(" Host name\n"); } else { printx(pkt,len); printf(" Value (too short)\n"); } break; } } static void val_vendor_name(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Vendor Name]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Vendor name\n"); break; } } static void val_assigned_tunnel_id(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Assigned Tunnel ID]"); break; case VFOP_VALUE: if (len == 2) { printx(pkt,2); printf(" ID\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_receive_window_size(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Receive Window Size]"); break; case VFOP_VALUE: if (len == 2) { unsigned int sz; sz = get16(0); printx(pkt,2); printf(" Window size [%u]\n",sz); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_challenge(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Challenge]"); break; case VFOP_VALUE: printx(pkt,len); printf(" Challenge\n"); break; } } static void val_q_931_cause_code(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Q.931 Cause Code]"); break; case VFOP_VALUE: if (len >= 3) { unsigned int code; unsigned int msg; code = get16(0); msg = get8(2); printx(pkt,2); printf(" Cause Code [%u]\n",code); printx(pkt+2,1); printf(" Cause Msg [%u]\n",msg); if (len > 3) { printxu(pkt+3,len-3); printf(" Advisory Msg\n"); } } else { printx(pkt,len); printf(" Value (too short)\n"); } break; } } static void val_challenge_response(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Challenge Response]"); break; case VFOP_VALUE: if (len == 16) { printx(pkt,16); printf(" Response\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_assigned_session_id(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Assigned Session ID]"); break; case VFOP_VALUE: if (len == 2) { printx(pkt,2); printf(" ID\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_call_serial_number(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Call Serial Number]"); break; case VFOP_VALUE: if (len == 4) { unsigned int ser; ser = get32(0); printx(pkt,4); printf(" Serial [%u]\n",ser); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_minimum_bps(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Minimum BPS]"); break; case VFOP_VALUE: if (len == 4) { unsigned int bps; bps = get32(0); printx(pkt,4); printf(" Speed [%u]\n",bps); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_maximum_bps(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Maximum BPS]"); break; case VFOP_VALUE: if (len == 4) { unsigned int bps; bps = get32(0); printx(pkt,4); printf(" Speed [%u]\n",bps); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_bearer_type(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Bearer Type]"); break; case VFOP_VALUE: if (len == 4) { unsigned int t; t = get32(0); printx(pkt,4); printf(" D=%d A=%d",t&1,(t>>1)&1); if (t & ~3U) printf(" (reserved %08x)",t&~3U); printf("\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_framing_type(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Framing Type]"); break; case VFOP_VALUE: if (len == 4) { unsigned int t; t = get32(0); printx(pkt,4); printf(" S=%d A=%d",t&1,(t>>1)&1); if (t & ~3U) printf(" (reserved %08x)",t&~3U); printf("\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_called_number(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Called Number]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Number\n"); break; } } static void val_calling_number(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Calling Number]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Number\n"); break; } } static void val_sub_address(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Sub-Address]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Number\n"); break; } } static void val_tx_connect_speed_bps(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [(Tx) Connect Speed]"); break; case VFOP_VALUE: if (len == 4) { unsigned int bps; bps = get32(0); printx(pkt,4); printf(" Speed [%u]\n",bps); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_physical_channel_id(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Physical Channel ID]"); break; case VFOP_VALUE: if (len == 4) { printx(pkt,4); printf(" ID\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_initial_received_lcp_confreq(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Initial Received LCP CONFREQ]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" CONFREQ packet\n"); break; } } static void val_last_sent_lcp_confreq(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Last Sent LCP CONFREQ]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" CONFREQ packet\n"); break; } } static void val_last_received_lcp_confreq(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Last Received LCP CONFREQ]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" CONFREQ packet\n"); break; } } static void val_proxy_authen_type(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Proxy Authen Type]"); break; case VFOP_VALUE: if (len == 2) { unsigned int t; t = get16(0); printx(pkt,2); printf(" Type [%u",t); switch (t) { case 1: printf(": plaintext username/password"); break; case 2: printf(": PPP CHAP"); break; case 3: printf(": PPP PAP"); break; case 4: printf(": None"); break; case 5: printf(": MSCHAPv1"); break; } printf("]\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_proxy_authen_name(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Proxy Authen Name]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Name\n"); break; } } static void val_proxy_authen_challenge(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Proxy Authen Challenge]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Challenge\n"); break; } } static void val_proxy_authen_id(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Proxy Authen ID]"); break; case VFOP_VALUE: if (len == 2) { unsigned int id; id = get16(0); printx(pkt,2); printf(" ID [%u]\n",id); if (id & 0xff00U) { printx(pkt,0); printf("*** Reserved bits set\n"); } } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_proxy_authen_response(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Proxy Authen Response]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" Response\n"); break; } } static void val_call_errors(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Call Errors]"); break; case VFOP_VALUE: if (len == 26) { printx(pkt,2); printf(" Reserved\n"); if (get16(0)) { printx(pkt,0); printf("*** Reserved field set\n"); } printx(pkt+2,4); printf(" CRC errors [%lu]\n",get32(2)); printx(pkt+6,4); printf(" Framing errors [%lu]\n",get32(6)); printx(pkt+10,4); printf(" Hardware overruns [%lu]\n",get32(10)); printx(pkt+14,4); printf(" Buffer overruns [%lu]\n",get32(14)); printx(pkt+18,4); printf(" Timeout errors [%lu]\n",get32(18)); printx(pkt+22,4); printf(" Alignment errors [%lu]\n",get32(22)); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_accm(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [ACCM]"); break; case VFOP_VALUE: if (len == 10) { printx(pkt,2); printf(" Reserved\n"); if (get16(0)) { printx(pkt,0); printf("*** Reserved field set\n"); } printx(pkt+2,4); printf(" Send ACCM\n"); printx(pkt+6,4); printf(" Receive ACCM\n"); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_random_vector(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Random Vector]"); break; case VFOP_VALUE: len=len; printf("Value\n"); break; } } static void val_private_group_id(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Private Group ID]"); break; case VFOP_VALUE: printxu(pkt,len); printf(" ID\n"); break; } } static void val_rx_connect_speed_bps(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Rx Connect Speed]"); break; case VFOP_VALUE: if (len == 4) { unsigned int bps; bps = get32(0); printx(pkt,4); printf(" Speed [%u]\n",bps); } else { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val_sequencing_required(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [Sequencing Required]"); break; case VFOP_VALUE: if (len != 0) { printx(pkt,len); printf(" Value (length wrong)\n"); } break; } } static void val__unrecognized(int op, int len) { switch (op) { case VFOP_PTYPE: printf(" [unrecognized]"); break; case VFOP_VALUE: printx(pkt,len); printf(" Value\n"); break; } } void dump_l2tp(void) { unsigned int flags; unsigned int len; unsigned int tunid; unsigned int sessid; unsigned int Ns; unsigned int Nr; unsigned int left; void (*valfn)(int, int); printx(pkt,0); printf("L2TP packet\n"); need(6,"minimum L2TP header"); flags = get16(0); printx(pkt,2); printf(" T=%d L=%d S=%d O=%d P=%d Ver=%d\n", (flags & HDR_F_T) ? 1 : 0, (flags & HDR_F_L) ? 1 : 0, (flags & HDR_F_S) ? 1 : 0, (flags & HDR_F_O) ? 1 : 0, (flags & HDR_F_P) ? 1 : 0, (flags >> HDR_F_VER_SHIFT) & HDR_F_VER_MASK ); if (((flags >> HDR_F_VER_SHIFT) & HDR_F_VER_MASK) != 2) { printx(pkt,0); printf("*** Version isn't 2\n"); dumpabort(); } if (flags & HDR_F_MBZ) { printx(pkt,0); printf("*** Ignoring reserved bits %04x\n",flags&HDR_F_MBZ); } if ( (flags & HDR_F_T) && ((flags & (HDR_F_L|HDR_F_S|HDR_F_O|HDR_F_P)) != (HDR_F_L|HDR_F_S)) ) { printx(pkt,0); printf("*** Invalid flags for control message (need L=1 S=1 O=0 P=0)\n"); } need(6+((flags&HDR_F_L)?2:0)+((flags&HDR_F_S)?2:0)+((flags&HDR_F_O)?2:0),"L2TP header"); consume(2); if (flags & HDR_F_L) { len = get16(0); printx(pkt,2); printf(" Length [%u]",len); consume(2); left = len - 4; if (left < pktleft) { int n; n = pktleft - left; printf(" (dropping %d trailing byte%s)",n,(n==1)?"":"s"); pktleft -= n; } else if (left > pktleft) { printf(" (%d-byte overrun)",left-pktleft); } printf("\n"); } else { left = pktleft; } tunid = get16(0); printx(pkt,2); printf(" Tunnel ID\n"); consume(2); sessid = get16(0); printx(pkt,2); printf(" Session ID\n"); consume(2); left -= 4; if (flags & HDR_F_S) { Ns = get16(0); printx(pkt,2); printf(" Ns\n"); consume(2); Nr = get16(0); printx(pkt,2); printf(" Nr\n"); consume(2); left -= 4; } if (flags & HDR_F_O) { unsigned int off; off = get16(0); printx(pkt,2); printf(" Offset size [%u]\n",off); consume(2); need(off,"offset padding"); printx(pkt,off); printf(" Offset padding\n"); consume(off); left -= off + 2; } need(left,"packet contents"); if (flags & HDR_F_T) { int avp; avp = 1; have_msgtype = 0; while (left > 0) { unsigned int flags; unsigned int len; unsigned int vendor; unsigned int type; need(6,"AVP header"); printx(pkt,0); printf(" AVP #%d\n",avp); flags = get16(0); len = (flags >> AVP_F_LEN_SHIFT) & AVP_F_LEN_MASK; printx(pkt,2); printf(" M=%d H=%d Length=%u\n", (flags & AVP_F_M) ? 1 : 0, (flags & AVP_F_H) ? 1 : 0, len ); consume(2); if (flags & AVP_F_MBZ) { printx(pkt,0); printf("*** Ignoring reserved bits %04x\n",flags&AVP_F_MBZ); } if (len < 6) { printx(pkt,0); printf("*** AVP length too short\n"); dumpabort(); } if ((flags & AVP_F_H) && (len < 8)) { printx(pkt,0); printf("*** Hidden AVP length too short\n"); dumpabort(); } if (len > left) { printx(pkt,0); printf("*** AVP overruns packet (overrun = %u)\n",len-left); dumpabort(); } vendor = get16(0); printx(pkt,2); printf(" Vendor ID"); if (vendor == 0) printf(" [standard]"); printf("\n"); consume(2); type = get16(0); printx(pkt,2); printf(" Attribute Type"); valfn = 0; if (vendor == 0) { switch (type) { case 0: valfn = &val_message_type; break; case 1: valfn = &val_result_code; break; case 2: valfn = &val_protocol_version; break; case 3: valfn = &val_framing_capabilities; break; case 4: valfn = &val_bearer_capabilities; break; case 5: valfn = &val_tie_breaker; break; case 6: valfn = &val_firmware_revision; break; case 7: valfn = &val_host_name; break; case 8: valfn = &val_vendor_name; break; case 9: valfn = &val_assigned_tunnel_id; break; case 10: valfn = &val_receive_window_size; break; case 11: valfn = &val_challenge; break; case 12: valfn = &val_q_931_cause_code; break; case 13: valfn = &val_challenge_response; break; case 14: valfn = &val_assigned_session_id; break; case 15: valfn = &val_call_serial_number; break; case 16: valfn = &val_minimum_bps; break; case 17: valfn = &val_maximum_bps; break; case 18: valfn = &val_bearer_type; break; case 19: valfn = &val_framing_type; break; case 21: valfn = &val_called_number; break; case 22: valfn = &val_calling_number; break; case 23: valfn = &val_sub_address; break; case 24: valfn = &val_tx_connect_speed_bps; break; case 25: valfn = &val_physical_channel_id; break; case 26: valfn = &val_initial_received_lcp_confreq; break; case 27: valfn = &val_last_sent_lcp_confreq; break; case 28: valfn = &val_last_received_lcp_confreq; break; case 29: valfn = &val_proxy_authen_type; break; case 30: valfn = &val_proxy_authen_name; break; case 31: valfn = &val_proxy_authen_challenge; break; case 32: valfn = &val_proxy_authen_id; break; case 33: valfn = &val_proxy_authen_response; break; case 34: valfn = &val_call_errors; break; case 35: valfn = &val_accm; break; case 36: valfn = &val_random_vector; break; case 37: valfn = &val_private_group_id; break; case 38: valfn = &val_rx_connect_speed_bps; break; case 39: valfn = &val_sequencing_required; break; default: valfn = &val__unrecognized; break; } } if (valfn) (*valfn)(VFOP_PTYPE,0); printf("\n"); consume(2); if (len > 6) { if (valfn) { if (flags & AVP_F_H) { printx(pkt,len-6); printf(" Value (hidden)\n"); } else { (*valfn)(VFOP_VALUE,len-6); } } else { printx(pkt,len-6); printf(" Value\n"); } } avp ++; consume(len-6); left -= len; } } }