/* $OpenBSD: print-ppp.c,v 1.16 2005/10/08 19:45:15 canacar Exp $ */ /* * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint static const char rcsid[] = "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-ppp.c,v 1.16 2005/10/08 19:45:15 canacar Exp $ (LBL)"; #endif #ifdef PPP #include #include #include #include #include struct mbuf; struct rtentry; #include #include #include #include #include #include #include #include #include #include #include #include #include "ethertype.h" #include #include "interface.h" #include "addrtoname.h" #include "extract.h" struct protonames { u_short protocol; char *name; }; static struct protonames protonames[] = { /* * Protocol field values. */ { PPP_IP, "IP" }, /* Internet Protocol */ { PPP_XNS, "XNS" }, /* Xerox NS */ { PPP_IPX, "IPX" }, /* IPX Datagram (RFC1552) */ { PPP_VJC_COMP, "VJC_UNCOMP" }, /* VJ compressed TCP */ { PPP_VJC_UNCOMP,"VJC_UNCOMP" },/* VJ uncompressed TCP */ { PPP_COMP, "COMP" }, /* compressed packet */ { PPP_IPCP, "IPCP" }, /* IP Control Protocol */ { PPP_IPXCP, "IPXCP" }, /* IPX Control Protocol (RFC1552) */ { PPP_CCP, "CCP" }, /* Compression Control Protocol */ { PPP_LCP, "LCP" }, /* Link Control Protocol */ { PPP_PAP, "PAP" }, /* Password Authentication Protocol */ { PPP_LQR, "LQR" }, /* Link Quality Report protocol */ { PPP_CHAP, "CHAP" }, /* Cryptographic Handshake Auth. Proto */ }; /* LCP */ #define LCP_CONF_REQ 1 #define LCP_CONF_ACK 2 #define LCP_CONF_NAK 3 #define LCP_CONF_REJ 4 #define LCP_TERM_REQ 5 #define LCP_TERM_ACK 6 #define LCP_CODE_REJ 7 #define LCP_PROT_REJ 8 #define LCP_ECHO_REQ 9 #define LCP_ECHO_RPL 10 #define LCP_DISC_REQ 11 #define LCP_MIN LCP_CONF_REQ #define LCP_MAX LCP_DISC_REQ static char *lcpcodes[] = { /* * LCP code values (RFC1661, pp26) */ "Configure-Request", "Configure-Ack", "Configure-Nak", "Configure-Reject", "Terminate-Request", "Terminate-Ack", "Code-Reject", "Protocol-Reject", "Echo-Request", "Echo-Reply", "Discard-Request", }; #define LCPOPT_VEXT 0 #define LCPOPT_MRU 1 #define LCPOPT_ACCM 2 #define LCPOPT_AP 3 #define LCPOPT_QP 4 #define LCPOPT_MN 5 #define LCPOPT_PFC 7 #define LCPOPT_ACFC 8 #define LCPOPT_MIN 0 #define LCPOPT_MAX 24 static char *lcpconfopts[] = { "Vendor-Ext", "Max-Rx-Unit", "Async-Ctrl-Char-Map", "Auth-Prot", "Quality-Prot", "Magic-Number", "unassigned (6)", "Prot-Field-Compr", "Add-Ctrl-Field-Compr", "FCS-Alternatives", "Self-Describing-Pad", "Numbered-Mode", "Multi-Link-Procedure", "Call-Back", "Connect-Time" "Compund-Frames", "Nominal-Data-Encap", "Multilink-MRRU", "Multilink-SSNHF", "Multilink-ED", "Proprietary", "DCE-Identifier", "Multilink-Plus-Proc", "Link-Discriminator", "LCP-Auth-Option", }; /* CHAP */ #define CHAP_CHAL 1 #define CHAP_RESP 2 #define CHAP_SUCC 3 #define CHAP_FAIL 4 #define CHAP_CODEMIN 1 #define CHAP_CODEMAX 4 static char *chapcode[] = { "Challenge", "Response", "Success", "Failure", }; /* PAP */ #define PAP_AREQ 1 #define PAP_AACK 2 #define PAP_ANAK 3 #define PAP_CODEMIN 1 #define PAP_CODEMAX 3 static char *papcode[] = { "Authenticate-Request", "Authenticate-Ack", "Authenticate-Nak", }; /* IPCP */ #define IPCP_CODE_CFG_REQ 1 #define IPCP_CODE_CFG_ACK 2 #define IPCP_CODE_CFG_NAK 3 #define IPCP_CODE_CFG_REJ 4 #define IPCP_CODE_TRM_REQ 5 #define IPCP_CODE_TRM_ACK 6 #define IPCP_CODE_COD_REJ 7 #define IPCP_CODE_MIN IPCP_CODE_CFG_REQ #define IPCP_CODE_MAX IPCP_CODE_COD_REJ #define IPCP_2ADDR 1 #define IPCP_CP 2 #define IPCP_ADDR 3 static int print_lcp_config_options(u_char *p); static void handle_lcp(const u_char *p, int length); static void handle_chap(const u_char *p, int length); static void handle_ipcp(const u_char *p, int length); static void handle_pap(const u_char *p, int length); struct pppoe_header { u_int8_t vertype; /* PPPoE version/type */ u_int8_t code; /* PPPoE code (packet type) */ u_int16_t sessionid; /* PPPoE session id */ u_int16_t len; /* PPPoE payload length */ }; #define PPPOE_CODE_SESSION 0x00 /* Session */ #define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ #define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ #define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ #define PPPOE_CODE_PADS 0x65 /* Active Discovery Session-Confirm */ #define PPPOE_CODE_PADT 0xa7 /* Active Discovery Terminate */ #define PPPOE_TAG_END_OF_LIST 0x0000 /* End Of List */ #define PPPOE_TAG_SERVICE_NAME 0x0101 /* Service Name */ #define PPPOE_TAG_AC_NAME 0x0102 /* Access Concentrator Name */ #define PPPOE_TAG_HOST_UNIQ 0x0103 /* Host Uniq */ #define PPPOE_TAG_AC_COOKIE 0x0104 /* Access Concentratr Cookie */ #define PPPOE_TAG_VENDOR_SPEC 0x0105 /* Vendor Specific */ #define PPPOE_TAG_RELAY_SESSION 0x0110 /* Relay Session Id */ #define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service Name Error */ #define PPPOE_TAG_AC_SYSTEM_ERROR 0x0202 /* Acc. Concentrator Error */ #define PPPOE_TAG_GENERIC_ERROR 0x0203 /* Generic Error */ void ppp_hdlc_print(p, length) const u_char *p; int length; { int proto = PPP_PROTOCOL(p); int i; printf("ID-%03d ", *(p+5)); for (i = sizeof(protonames) / sizeof(protonames[0]) - 1; i >= 0; i--) { if (proto == protonames[i].protocol) { printf("%s: ", protonames[i].name); switch(proto) { case PPP_LCP: handle_lcp(p, length); break; case PPP_CHAP: handle_chap(p, length); break; case PPP_PAP: handle_pap(p, length); break; case PPP_IPCP: handle_ipcp(p, length); break; } break; } } if (i < 0) printf("%04x: ", proto); } /* print LCP frame */ static void handle_lcp(p, length) const u_char *p; int length; { int x, j; u_char *ptr; x = *(p + 4); if ((x >= LCP_MIN) && (x <= LCP_MAX)) printf("%s", lcpcodes[x-1]); else { printf("0x%02x", x); return; } length -= 4; switch(x) { case LCP_CONF_REQ: case LCP_CONF_ACK: case LCP_CONF_NAK: case LCP_CONF_REJ: x = length; ptr = (u_char *)p+8; do { if((j = print_lcp_config_options(ptr)) == 0) break; x -= j; ptr += j; } while(x > 0); break; case LCP_ECHO_REQ: case LCP_ECHO_RPL: printf(", Magic-Number=%d", ((*(p+ 8) << 24) + (*(p+9) << 16) + (*(p+10) << 8) + (*(p+11)))); break; case LCP_TERM_REQ: case LCP_TERM_ACK: case LCP_CODE_REJ: case LCP_PROT_REJ: case LCP_DISC_REQ: default: break; } } /* LCP config options */ static int print_lcp_config_options(p) u_char *p; { int len = *(p+1); int opt = *p; if((opt >= LCPOPT_MIN) && (opt <= LCPOPT_MAX)) printf(", %s", lcpconfopts[opt]); switch(opt) { case LCPOPT_MRU: if(len == 4) printf("=%d", (*(p+2) << 8) + *(p+3)); break; case LCPOPT_AP: if(len >= 4) { if(*(p+2) == 0xc0 && *(p+3) == 0x23) printf(" PAP"); else if(*(p+2) == 0xc2 && *(p+3) == 0x23) { printf(" CHAP/"); switch(*(p+4)) { default: printf("unknown-algorithm-%d", *(p+4)); break; case 5: printf("MD5"); break; case 0x80: printf("Microsoft"); break; } } else if(*(p+2) == 0xc2 && *(p+3) == 0x27) printf(" EAP"); else if(*(p+2) == 0xc0 && *(p+3) == 0x27) printf(" SPAP"); else if(*(p+2) == 0xc1 && *(p+3) == 0x23) printf(" Old-SPAP"); else printf("unknown"); } break; case LCPOPT_QP: if(len >= 4) { if(*(p+2) == 0xc0 && *(p+3) == 0x25) printf(" LQR"); else printf(" unknown"); } break; case LCPOPT_MN: if(len == 6) printf("=%d", ((*(p+2) << 24) + (*(p+3) << 16) + (*(p+4) << 8) + (*(p+5)))); break; case LCPOPT_PFC: printf(" PFC"); break; case LCPOPT_ACFC: printf(" ACFC"); break; } return(len); } /* CHAP */ static void handle_chap(p, length) const u_char *p; int length; { int x; u_char *ptr; x = *(p+4); if((x >= CHAP_CODEMIN) && (x <= CHAP_CODEMAX)) printf("%s", chapcode[x-1]); else { printf("0x%02x", x); return; } length -= 4; switch(x) { case CHAP_CHAL: case CHAP_RESP: printf(", Value="); x = *(p+8); /* value size */ ptr = (u_char *)p+9; while(--x >= 0) printf("%02x", *ptr++); x = length - *(p+8) - 1; printf(", Name="); while(--x >= 0) printf("%c", *ptr++); break; } } /* PAP */ static void handle_pap(p, length) const u_char *p; int length; { int x; u_char *ptr; x = *(p+4); if((x >= PAP_CODEMIN) && (x <= PAP_CODEMAX)) printf("%s", papcode[x-1]); else { printf("0x%02x", x); return; } length -= 4; switch(x) { case PAP_AREQ: printf(", Peer-Id="); x = *(p+8); /* peerid size */ ptr = (u_char *)p+9; while(--x >= 0) printf("%c", *ptr++); x = *ptr++; printf(", Passwd="); while(--x >= 0) printf("%c", *ptr++); break; case PAP_AACK: case PAP_ANAK: break; } } /* IPCP */ static void handle_ipcp(p, length) const u_char *p; int length; { int x; x = *(p+4); if((x >= IPCP_CODE_MIN) && (x <= IPCP_CODE_MAX)) printf("%s", lcpcodes[x-1]); /* share table with LCP */ else { printf("0x%02x", x); return; } length -= 4; switch(*(p+8)) { case IPCP_2ADDR: printf(", IP-Addresses"); printf(", Src=%d.%d.%d.%d", *(p+10), *(p+11), *(p+12), *(p+13)); printf(", Dst=%d.%d.%d.%d", *(p+14), *(p+15), *(p+16), *(p+17)); break; case IPCP_CP: printf(", IP-Compression-Protocol"); break; case IPCP_ADDR: printf(", IP-Address=%d.%d.%d.%d", *(p+10), *(p+11), *(p+12), *(p+13)); break; default: printf(", Unknown IPCP code 0x%x", *(p+8)); break; } } void ppp_if_print(user, h, p) u_char *user; const struct pcap_pkthdr *h; register const u_char *p; { register u_int length = h->len; register u_int caplen = h->caplen; ts_print(&h->ts); if (caplen < PPP_HDRLEN) { printf("[|ppp]"); goto out; } /* * Some printers want to get back at the link level addresses, * and/or check that they're not walking off the end of the packet. * Rather than pass them all the way down, we set these globals. */ packetp = p; snapend = p + caplen; if (eflag) ppp_hdlc_print(p, length); length -= PPP_HDRLEN; switch(PPP_PROTOCOL(p)) { case PPP_IP: case ETHERTYPE_IP: ip_print((const u_char *)(p + PPP_HDRLEN), length); break; case PPP_IPX: case ETHERTYPE_IPX: ipx_print((const u_char *)(p + PPP_HDRLEN), length); break; #ifndef PPP_MPLS #define PPP_MPLS 0x0281 #endif case PPP_MPLS: mpls_print((const u_char *)(p + PPP_HDRLEN), length); break; default: if(!eflag) ppp_hdlc_print(p, length); if(!xflag) default_print((const u_char *)(p + PPP_HDRLEN), caplen - PPP_HDRLEN); } if (xflag) default_print((const u_char *)(p + PPP_HDRLEN), caplen - PPP_HDRLEN); out: putchar('\n'); } void ppp_ether_if_print(user, h, p) u_char *user; const struct pcap_pkthdr *h; register const u_char *p; { u_int16_t pppoe_sid, pppoe_len; u_int caplen = h->caplen; u_int16_t length = h->len; u_int16_t proto; int i; ts_print(&h->ts); packetp = p; snapend = p + caplen; if (eflag) printf("PPPoE "); if (caplen < sizeof(struct pppoe_header)) { printf("[|pppoe]"); return; } if(eflag) { printf("\n\tcode "); switch (p[1]) { case PPPOE_CODE_PADI: printf("Initiation"); break; case PPPOE_CODE_PADO: printf("Offer"); break; case PPPOE_CODE_PADR: printf("Request"); break; case PPPOE_CODE_PADS: printf("Confirm"); break; case PPPOE_CODE_PADT: printf("Terminate"); break; case PPPOE_CODE_SESSION: printf("Session"); break; default: printf("Unknown(0x%02x)", p[1]); break; } } pppoe_sid = EXTRACT_16BITS(p + 2); pppoe_len = EXTRACT_16BITS(p + 4); if(eflag) printf(", version %d, type %d, id 0x%04x, length %d", (p[0] & 0xf), (p[0] & 0xf0) >> 4, pppoe_sid, pppoe_len); length -= sizeof(struct pppoe_header); caplen -= sizeof(struct pppoe_header); p += sizeof(struct pppoe_header); if (pppoe_len > caplen) pppoe_len = caplen; if (pppoe_len < 2) { printf("[|pppoe]"); return; } proto = EXTRACT_16BITS(p); for (i = sizeof(protonames)/sizeof(protonames[0]) - 1; i >= 0; i--) { if (proto == protonames[i].protocol) { if (eflag) printf("\n\t%s: ", protonames[i].name); switch (proto) { case PPP_LCP: handle_lcp(p - 2, length + 2); break; case PPP_CHAP: handle_chap(p - 2, length + 2); break; case PPP_PAP: handle_pap(p - 2, length + 2); break; case PPP_IPCP: handle_ipcp(p - 2, length + 2); break; case PPP_IP: ip_print(p + 2, length - 2); break; case PPP_IPX: ipx_print(p + 2, length - 2); } break; } } if (i < 0) printf("\n\t%04x: ", proto); if (xflag) default_print((const u_char *) (p + sizeof(struct pppoe_header)), caplen - sizeof(struct pppoe_header)); putchar('\n'); } int pppoe_if_print(ethertype, p, length, caplen) u_short ethertype; const u_char *p; u_int length, caplen; { u_int16_t pppoe_sid, pppoe_len; if (ethertype == ETHERTYPE_PPPOEDISC) printf("PPPoE-Discovery"); else printf("PPPoE-Session"); if (caplen < sizeof(struct pppoe_header)) { printf("[|pppoe]"); return (1); } printf("\n\tcode "); switch (p[1]) { case PPPOE_CODE_PADI: printf("Initiation"); break; case PPPOE_CODE_PADO: printf("Offer"); break; case PPPOE_CODE_PADR: printf("Request"); break; case PPPOE_CODE_PADS: printf("Confirm"); break; case PPPOE_CODE_PADT: printf("Terminate"); break; case PPPOE_CODE_SESSION: printf("Session"); break; default: printf("Unknown(0x%02x)", p[1]); break; } pppoe_sid = EXTRACT_16BITS(p + 2); pppoe_len = EXTRACT_16BITS(p + 4); printf(", version %d, type %d, id 0x%04x, length %d", (p[0] & 0xf), (p[0] & 0xf0) >> 4, pppoe_sid, pppoe_len); length -= sizeof(struct pppoe_header); caplen -= sizeof(struct pppoe_header); p += sizeof(struct pppoe_header); if (pppoe_len > caplen) pppoe_len = caplen; if (ethertype == ETHERTYPE_PPPOEDISC) { while (pppoe_len > 0) { u_int16_t t_type, t_len; if (pppoe_len < 4) { printf("\n\t[|pppoe]"); break; } t_type = EXTRACT_16BITS(p); t_len = EXTRACT_16BITS(p + 2); pppoe_len -= 4; p += 4; if (pppoe_len < t_len) { printf("\n\t[|pppoe]"); break; } printf("\n\ttag "); switch (t_type) { case PPPOE_TAG_END_OF_LIST: printf("End-Of-List"); break; case PPPOE_TAG_SERVICE_NAME: printf("Service-Name"); break; case PPPOE_TAG_AC_NAME: printf("AC-Name"); break; case PPPOE_TAG_HOST_UNIQ: printf("Host-Uniq"); break; case PPPOE_TAG_AC_COOKIE: printf("AC-Cookie"); break; case PPPOE_TAG_VENDOR_SPEC: printf("Vendor-Specific"); break; case PPPOE_TAG_RELAY_SESSION: printf("Relay-Session"); break; case PPPOE_TAG_SERVICE_NAME_ERROR: printf("Service-Name-Error"); break; case PPPOE_TAG_AC_SYSTEM_ERROR: printf("AC-System-Error"); break; case PPPOE_TAG_GENERIC_ERROR: printf("Generic-Error"); break; default: printf("Unknown(0x%04x)", t_type); } printf(", length %u%s", t_len, t_len ? " " : ""); if (t_len) { for (t_type = 0; t_type < t_len; t_type++) { if (isprint(p[t_type])) printf("%c", p[t_type]); else printf("\\%03o", p[t_type]); } } pppoe_len -= t_len; p += t_len; } } else if (ethertype == ETHERTYPE_PPPOE) { u_int16_t proto; int i; if (pppoe_len < 2) { printf("[|pppoe]"); return (1); } proto = EXTRACT_16BITS(p); for (i = sizeof(protonames)/sizeof(protonames[0]) - 1; i >= 0; i--) { if (proto == protonames[i].protocol) { printf("\n\t%s: ", protonames[i].name); switch (proto) { case PPP_LCP: handle_lcp(p - 2, length + 2); break; case PPP_CHAP: handle_chap(p - 2, length + 2); break; case PPP_PAP: handle_pap(p - 2, length + 2); break; case PPP_IPCP: handle_ipcp(p - 2, length + 2); break; case PPP_IP: ip_print(p + 2, length - 2); break; case PPP_IPX: ipx_print(p + 2, length - 2); } break; } } if (i < 0) printf("\n\t%04x: ", proto); } return (1); } #else #include #include #include #include "interface.h" void ppp_if_print(user, h, p) u_char *user; const struct pcap_pkthdr *h; const u_char *p; { error("not configured for ppp"); /* NOTREACHED */ } #endif