Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (C) 2000 Alfredo Andres Omella.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  *   1. Redistributions of source code must retain the above copyright
      9  *      notice, this list of conditions and the following disclaimer.
     10  *   2. Redistributions in binary form must reproduce the above copyright
     11  *      notice, this list of conditions and the following disclaimer in
     12  *      the documentation and/or other materials provided with the
     13  *      distribution.
     14  *   3. The names of the authors may not be used to endorse or promote
     15  *      products derived from this software without specific prior
     16  *      written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     21  */
     22 /*
     23  * Radius printer routines as specified on:
     24  *
     25  * RFC 2865:
     26  *      "Remote Authentication Dial In User Service (RADIUS)"
     27  *
     28  * RFC 2866:
     29  *      "RADIUS Accounting"
     30  *
     31  * RFC 2867:
     32  *      "RADIUS Accounting Modifications for Tunnel Protocol Support"
     33  *
     34  * RFC 2868:
     35  *      "RADIUS Attributes for Tunnel Protocol Support"
     36  *
     37  * RFC 2869:
     38  *      "RADIUS Extensions"
     39  *
     40  * RFC 4675:
     41  *      "RADIUS Attributes for Virtual LAN and Priority Support"
     42  *
     43  * RFC 5176:
     44  *      "Dynamic Authorization Extensions to RADIUS"
     45  *
     46  * Alfredo Andres Omella (aandres (at) s21sec.com) v0.1 2000/09/15
     47  *
     48  * TODO: Among other things to print ok MacIntosh and Vendor values
     49  */
     50 
     51 #define NETDISSECT_REWORKED
     52 #ifdef HAVE_CONFIG_H
     53 #include "config.h"
     54 #endif
     55 
     56 #include <tcpdump-stdinc.h>
     57 
     58 #include <string.h>
     59 
     60 #include "interface.h"
     61 #include "addrtoname.h"
     62 #include "extract.h"
     63 #include "oui.h"
     64 
     65 static const char tstr[] = " [|radius]";
     66 
     67 #define TAM_SIZE(x) (sizeof(x)/sizeof(x[0]) )
     68 
     69 #define PRINT_HEX(bytes_len, ptr_data)                               \
     70            while(bytes_len)                                          \
     71            {                                                         \
     72               ND_PRINT((ndo, "%02X", *ptr_data ));                   \
     73               ptr_data++;                                            \
     74               bytes_len--;                                           \
     75            }
     76 
     77 
     78 /* Radius packet codes */
     79 #define RADCMD_ACCESS_REQ   1 /* Access-Request      */
     80 #define RADCMD_ACCESS_ACC   2 /* Access-Accept       */
     81 #define RADCMD_ACCESS_REJ   3 /* Access-Reject       */
     82 #define RADCMD_ACCOUN_REQ   4 /* Accounting-Request  */
     83 #define RADCMD_ACCOUN_RES   5 /* Accounting-Response */
     84 #define RADCMD_ACCESS_CHA  11 /* Access-Challenge    */
     85 #define RADCMD_STATUS_SER  12 /* Status-Server       */
     86 #define RADCMD_STATUS_CLI  13 /* Status-Client       */
     87 #define RADCMD_DISCON_REQ  40 /* Disconnect-Request  */
     88 #define RADCMD_DISCON_ACK  41 /* Disconnect-ACK      */
     89 #define RADCMD_DISCON_NAK  42 /* Disconnect-NAK      */
     90 #define RADCMD_COA_REQ     43 /* CoA-Request         */
     91 #define RADCMD_COA_ACK     44 /* CoA-ACK             */
     92 #define RADCMD_COA_NAK     45 /* CoA-NAK             */
     93 #define RADCMD_RESERVED   255 /* Reserved            */
     94 
     95 static const struct tok radius_command_values[] = {
     96     { RADCMD_ACCESS_REQ, "Access-Request" },
     97     { RADCMD_ACCESS_ACC, "Access-Accept" },
     98     { RADCMD_ACCESS_REJ, "Access-Reject" },
     99     { RADCMD_ACCOUN_REQ, "Accounting-Request" },
    100     { RADCMD_ACCOUN_RES, "Accounting-Response" },
    101     { RADCMD_ACCESS_CHA, "Access-Challenge" },
    102     { RADCMD_STATUS_SER, "Status-Server" },
    103     { RADCMD_STATUS_CLI, "Status-Client" },
    104     { RADCMD_DISCON_REQ, "Disconnect-Request" },
    105     { RADCMD_DISCON_ACK, "Disconnect-ACK" },
    106     { RADCMD_DISCON_NAK, "Disconnect-NAK" },
    107     { RADCMD_COA_REQ,    "CoA-Request" },
    108     { RADCMD_COA_ACK,    "CoA-ACK" },
    109     { RADCMD_COA_NAK,    "CoA-NAK" },
    110     { RADCMD_RESERVED,   "Reserved" },
    111     { 0, NULL}
    112 };
    113 
    114 /********************************/
    115 /* Begin Radius Attribute types */
    116 /********************************/
    117 #define SERV_TYPE    6
    118 #define FRM_IPADDR   8
    119 #define LOG_IPHOST  14
    120 #define LOG_SERVICE 15
    121 #define FRM_IPX     23
    122 #define SESSION_TIMEOUT   27
    123 #define IDLE_TIMEOUT      28
    124 #define FRM_ATALK_LINK    37
    125 #define FRM_ATALK_NETWORK 38
    126 
    127 #define ACCT_DELAY        41
    128 #define ACCT_SESSION_TIME 46
    129 
    130 #define EGRESS_VLAN_ID   56
    131 #define EGRESS_VLAN_NAME 58
    132 
    133 #define TUNNEL_TYPE        64
    134 #define TUNNEL_MEDIUM      65
    135 #define TUNNEL_CLIENT_END  66
    136 #define TUNNEL_SERVER_END  67
    137 #define TUNNEL_PASS        69
    138 
    139 #define ARAP_PASS          70
    140 #define ARAP_FEATURES      71
    141 
    142 #define TUNNEL_PRIV_GROUP  81
    143 #define TUNNEL_ASSIGN_ID   82
    144 #define TUNNEL_PREFERENCE  83
    145 
    146 #define ARAP_CHALLENGE_RESP 84
    147 #define ACCT_INT_INTERVAL   85
    148 
    149 #define TUNNEL_CLIENT_AUTH 90
    150 #define TUNNEL_SERVER_AUTH 91
    151 /********************************/
    152 /* End Radius Attribute types */
    153 /********************************/
    154 
    155 #define RFC4675_TAGGED   0x31
    156 #define RFC4675_UNTAGGED 0x32
    157 
    158 static const struct tok rfc4675_tagged[] = {
    159     { RFC4675_TAGGED,   "Tagged" },
    160     { RFC4675_UNTAGGED, "Untagged" },
    161     { 0, NULL}
    162 };
    163 
    164 
    165 static void print_attr_string(netdissect_options *, register u_char *, u_int, u_short );
    166 static void print_attr_num(netdissect_options *, register u_char *, u_int, u_short );
    167 static void print_vendor_attr(netdissect_options *, register u_char *, u_int, u_short );
    168 static void print_attr_address(netdissect_options *, register u_char *, u_int, u_short);
    169 static void print_attr_time(netdissect_options *, register u_char *, u_int, u_short);
    170 static void print_attr_strange(netdissect_options *, register u_char *, u_int, u_short);
    171 
    172 
    173 struct radius_hdr { uint8_t  code; /* Radius packet code  */
    174                     uint8_t  id;   /* Radius packet id    */
    175                     uint16_t len;  /* Radius total length */
    176                     uint8_t  auth[16]; /* Authenticator   */
    177                   };
    178 
    179 #define MIN_RADIUS_LEN	20
    180 
    181 struct radius_attr { uint8_t type; /* Attribute type   */
    182                      uint8_t len;  /* Attribute length */
    183                    };
    184 
    185 
    186 /* Service-Type Attribute standard values */
    187 static const char *serv_type[]={ NULL,
    188                                 "Login",
    189                                 "Framed",
    190                                 "Callback Login",
    191                                 "Callback Framed",
    192                                 "Outbound",
    193                                 "Administrative",
    194                                 "NAS Prompt",
    195                                 "Authenticate Only",
    196                                 "Callback NAS Prompt",
    197                                 "Call Check",
    198                                 "Callback Administrative",
    199                                };
    200 
    201 /* Framed-Protocol Attribute standard values */
    202 static const char *frm_proto[]={ NULL,
    203                                  "PPP",
    204                                  "SLIP",
    205                                  "ARAP",
    206                                  "Gandalf proprietary",
    207                                  "Xylogics IPX/SLIP",
    208                                  "X.75 Synchronous",
    209                                };
    210 
    211 /* Framed-Routing Attribute standard values */
    212 static const char *frm_routing[]={ "None",
    213                                    "Send",
    214                                    "Listen",
    215                                    "Send&Listen",
    216                                  };
    217 
    218 /* Framed-Compression Attribute standard values */
    219 static const char *frm_comp[]={ "None",
    220                                 "VJ TCP/IP",
    221                                 "IPX",
    222                                 "Stac-LZS",
    223                               };
    224 
    225 /* Login-Service Attribute standard values */
    226 static const char *login_serv[]={ "Telnet",
    227                                   "Rlogin",
    228                                   "TCP Clear",
    229                                   "PortMaster(proprietary)",
    230                                   "LAT",
    231                                   "X.25-PAD",
    232                                   "X.25-T3POS",
    233                                   "Unassigned",
    234                                   "TCP Clear Quiet",
    235                                 };
    236 
    237 
    238 /* Termination-Action Attribute standard values */
    239 static const char *term_action[]={ "Default",
    240                                    "RADIUS-Request",
    241                                  };
    242 
    243 /* Ingress-Filters Attribute standard values */
    244 static const char *ingress_filters[]={ NULL,
    245                                        "Enabled",
    246                                        "Disabled",
    247                                      };
    248 
    249 /* NAS-Port-Type Attribute standard values */
    250 static const char *nas_port_type[]={ "Async",
    251                                      "Sync",
    252                                      "ISDN Sync",
    253                                      "ISDN Async V.120",
    254                                      "ISDN Async V.110",
    255                                      "Virtual",
    256                                      "PIAFS",
    257                                      "HDLC Clear Channel",
    258                                      "X.25",
    259                                      "X.75",
    260                                      "G.3 Fax",
    261                                      "SDSL",
    262                                      "ADSL-CAP",
    263                                      "ADSL-DMT",
    264                                      "ISDN-DSL",
    265                                      "Ethernet",
    266                                      "xDSL",
    267                                      "Cable",
    268                                      "Wireless - Other",
    269                                      "Wireless - IEEE 802.11",
    270                                    };
    271 
    272 /* Acct-Status-Type Accounting Attribute standard values */
    273 static const char *acct_status[]={ NULL,
    274                                    "Start",
    275                                    "Stop",
    276                                    "Interim-Update",
    277                                    "Unassigned",
    278                                    "Unassigned",
    279                                    "Unassigned",
    280                                    "Accounting-On",
    281                                    "Accounting-Off",
    282                                    "Tunnel-Start",
    283                                    "Tunnel-Stop",
    284                                    "Tunnel-Reject",
    285                                    "Tunnel-Link-Start",
    286                                    "Tunnel-Link-Stop",
    287                                    "Tunnel-Link-Reject",
    288                                    "Failed",
    289                                  };
    290 
    291 /* Acct-Authentic Accounting Attribute standard values */
    292 static const char *acct_auth[]={ NULL,
    293                                  "RADIUS",
    294                                  "Local",
    295                                  "Remote",
    296                                };
    297 
    298 /* Acct-Terminate-Cause Accounting Attribute standard values */
    299 static const char *acct_term[]={ NULL,
    300                                  "User Request",
    301                                  "Lost Carrier",
    302                                  "Lost Service",
    303                                  "Idle Timeout",
    304                                  "Session Timeout",
    305                                  "Admin Reset",
    306                                  "Admin Reboot",
    307                                  "Port Error",
    308                                  "NAS Error",
    309                                  "NAS Request",
    310                                  "NAS Reboot",
    311                                  "Port Unneeded",
    312                                  "Port Preempted",
    313                                  "Port Suspended",
    314                                  "Service Unavailable",
    315                                  "Callback",
    316                                  "User Error",
    317                                  "Host Request",
    318                                };
    319 
    320 /* Tunnel-Type Attribute standard values */
    321 static const char *tunnel_type[]={ NULL,
    322                                    "PPTP",
    323                                    "L2F",
    324                                    "L2TP",
    325                                    "ATMP",
    326                                    "VTP",
    327                                    "AH",
    328                                    "IP-IP",
    329                                    "MIN-IP-IP",
    330                                    "ESP",
    331                                    "GRE",
    332                                    "DVS",
    333                                    "IP-in-IP Tunneling",
    334                                  };
    335 
    336 /* Tunnel-Medium-Type Attribute standard values */
    337 static const char *tunnel_medium[]={ NULL,
    338                                      "IPv4",
    339                                      "IPv6",
    340                                      "NSAP",
    341                                      "HDLC",
    342                                      "BBN 1822",
    343                                      "802",
    344                                      "E.163",
    345                                      "E.164",
    346                                      "F.69",
    347                                      "X.121",
    348                                      "IPX",
    349                                      "Appletalk",
    350                                      "Decnet IV",
    351                                      "Banyan Vines",
    352                                      "E.164 with NSAP subaddress",
    353                                    };
    354 
    355 /* ARAP-Zone-Access Attribute standard values */
    356 static const char *arap_zone[]={ NULL,
    357                                  "Only access to dfl zone",
    358                                  "Use zone filter inc.",
    359                                  "Not used",
    360                                  "Use zone filter exc.",
    361                                };
    362 
    363 static const char *prompt[]={ "No Echo",
    364                               "Echo",
    365                             };
    366 
    367 
    368 struct attrtype { const char *name;      /* Attribute name                 */
    369                   const char **subtypes; /* Standard Values (if any)       */
    370                   u_char siz_subtypes;   /* Size of total standard values  */
    371                   u_char first_subtype;  /* First standard value is 0 or 1 */
    372                   void (*print_func)(netdissect_options *, register u_char *, u_int, u_short);
    373                 } attr_type[]=
    374   {
    375      { NULL,                              NULL, 0, 0, NULL               },
    376      { "User-Name",                       NULL, 0, 0, print_attr_string  },
    377      { "User-Password",                   NULL, 0, 0, NULL               },
    378      { "CHAP-Password",                   NULL, 0, 0, NULL               },
    379      { "NAS-IP-Address",                  NULL, 0, 0, print_attr_address },
    380      { "NAS-Port",                        NULL, 0, 0, print_attr_num     },
    381      { "Service-Type",                    serv_type, TAM_SIZE(serv_type)-1, 1, print_attr_num },
    382      { "Framed-Protocol",                 frm_proto, TAM_SIZE(frm_proto)-1, 1, print_attr_num },
    383      { "Framed-IP-Address",               NULL, 0, 0, print_attr_address },
    384      { "Framed-IP-Netmask",               NULL, 0, 0, print_attr_address },
    385      { "Framed-Routing",                  frm_routing, TAM_SIZE(frm_routing), 0, print_attr_num },
    386      { "Filter-Id",                       NULL, 0, 0, print_attr_string  },
    387      { "Framed-MTU",                      NULL, 0, 0, print_attr_num     },
    388      { "Framed-Compression",              frm_comp, TAM_SIZE(frm_comp),   0, print_attr_num },
    389      { "Login-IP-Host",                   NULL, 0, 0, print_attr_address },
    390      { "Login-Service",                   login_serv, TAM_SIZE(login_serv), 0, print_attr_num },
    391      { "Login-TCP-Port",                  NULL, 0, 0, print_attr_num     },
    392      { "Unassigned",                      NULL, 0, 0, NULL }, /*17*/
    393      { "Reply-Message",                   NULL, 0, 0, print_attr_string },
    394      { "Callback-Number",                 NULL, 0, 0, print_attr_string },
    395      { "Callback-Id",                     NULL, 0, 0, print_attr_string },
    396      { "Unassigned",                      NULL, 0, 0, NULL }, /*21*/
    397      { "Framed-Route",                    NULL, 0, 0, print_attr_string },
    398      { "Framed-IPX-Network",              NULL, 0, 0, print_attr_num    },
    399      { "State",                           NULL, 0, 0, print_attr_string },
    400      { "Class",                           NULL, 0, 0, print_attr_string },
    401      { "Vendor-Specific",                 NULL, 0, 0, print_vendor_attr },
    402      { "Session-Timeout",                 NULL, 0, 0, print_attr_num    },
    403      { "Idle-Timeout",                    NULL, 0, 0, print_attr_num    },
    404      { "Termination-Action",              term_action, TAM_SIZE(term_action), 0, print_attr_num },
    405      { "Called-Station-Id",               NULL, 0, 0, print_attr_string },
    406      { "Calling-Station-Id",              NULL, 0, 0, print_attr_string },
    407      { "NAS-Identifier",                  NULL, 0, 0, print_attr_string },
    408      { "Proxy-State",                     NULL, 0, 0, print_attr_string },
    409      { "Login-LAT-Service",               NULL, 0, 0, print_attr_string },
    410      { "Login-LAT-Node",                  NULL, 0, 0, print_attr_string },
    411      { "Login-LAT-Group",                 NULL, 0, 0, print_attr_string },
    412      { "Framed-AppleTalk-Link",           NULL, 0, 0, print_attr_num    },
    413      { "Framed-AppleTalk-Network",        NULL, 0, 0, print_attr_num    },
    414      { "Framed-AppleTalk-Zone",           NULL, 0, 0, print_attr_string },
    415      { "Acct-Status-Type",                acct_status, TAM_SIZE(acct_status)-1, 1, print_attr_num },
    416      { "Acct-Delay-Time",                 NULL, 0, 0, print_attr_num    },
    417      { "Acct-Input-Octets",               NULL, 0, 0, print_attr_num    },
    418      { "Acct-Output-Octets",              NULL, 0, 0, print_attr_num    },
    419      { "Acct-Session-Id",                 NULL, 0, 0, print_attr_string },
    420      { "Acct-Authentic",                  acct_auth, TAM_SIZE(acct_auth)-1, 1, print_attr_num },
    421      { "Acct-Session-Time",               NULL, 0, 0, print_attr_num },
    422      { "Acct-Input-Packets",              NULL, 0, 0, print_attr_num },
    423      { "Acct-Output-Packets",             NULL, 0, 0, print_attr_num },
    424      { "Acct-Terminate-Cause",            acct_term, TAM_SIZE(acct_term)-1, 1, print_attr_num },
    425      { "Acct-Multi-Session-Id",           NULL, 0, 0, print_attr_string },
    426      { "Acct-Link-Count",                 NULL, 0, 0, print_attr_num },
    427      { "Acct-Input-Gigawords",            NULL, 0, 0, print_attr_num },
    428      { "Acct-Output-Gigawords",           NULL, 0, 0, print_attr_num },
    429      { "Unassigned",                      NULL, 0, 0, NULL }, /*54*/
    430      { "Event-Timestamp",                 NULL, 0, 0, print_attr_time },
    431      { "Egress-VLANID",                   NULL, 0, 0, print_attr_num },
    432      { "Ingress-Filters",                 ingress_filters, TAM_SIZE(ingress_filters)-1, 1, print_attr_num },
    433      { "Egress-VLAN-Name",                NULL, 0, 0, print_attr_string },
    434      { "User-Priority-Table",             NULL, 0, 0, NULL },
    435      { "CHAP-Challenge",                  NULL, 0, 0, print_attr_string },
    436      { "NAS-Port-Type",                   nas_port_type, TAM_SIZE(nas_port_type), 0, print_attr_num },
    437      { "Port-Limit",                      NULL, 0, 0, print_attr_num },
    438      { "Login-LAT-Port",                  NULL, 0, 0, print_attr_string }, /*63*/
    439      { "Tunnel-Type",                     tunnel_type, TAM_SIZE(tunnel_type)-1, 1, print_attr_num },
    440      { "Tunnel-Medium-Type",              tunnel_medium, TAM_SIZE(tunnel_medium)-1, 1, print_attr_num },
    441      { "Tunnel-Client-Endpoint",          NULL, 0, 0, print_attr_string },
    442      { "Tunnel-Server-Endpoint",          NULL, 0, 0, print_attr_string },
    443      { "Acct-Tunnel-Connection",          NULL, 0, 0, print_attr_string },
    444      { "Tunnel-Password",                 NULL, 0, 0, print_attr_string  },
    445      { "ARAP-Password",                   NULL, 0, 0, print_attr_strange },
    446      { "ARAP-Features",                   NULL, 0, 0, print_attr_strange },
    447      { "ARAP-Zone-Access",                arap_zone, TAM_SIZE(arap_zone)-1, 1, print_attr_num }, /*72*/
    448      { "ARAP-Security",                   NULL, 0, 0, print_attr_string },
    449      { "ARAP-Security-Data",              NULL, 0, 0, print_attr_string },
    450      { "Password-Retry",                  NULL, 0, 0, print_attr_num    },
    451      { "Prompt",                          prompt, TAM_SIZE(prompt), 0, print_attr_num },
    452      { "Connect-Info",                    NULL, 0, 0, print_attr_string   },
    453      { "Configuration-Token",             NULL, 0, 0, print_attr_string   },
    454      { "EAP-Message",                     NULL, 0, 0, print_attr_string   },
    455      { "Message-Authenticator",           NULL, 0, 0, print_attr_string }, /*80*/
    456      { "Tunnel-Private-Group-ID",         NULL, 0, 0, print_attr_string },
    457      { "Tunnel-Assignment-ID",            NULL, 0, 0, print_attr_string },
    458      { "Tunnel-Preference",               NULL, 0, 0, print_attr_num    },
    459      { "ARAP-Challenge-Response",         NULL, 0, 0, print_attr_strange },
    460      { "Acct-Interim-Interval",           NULL, 0, 0, print_attr_num     },
    461      { "Acct-Tunnel-Packets-Lost",        NULL, 0, 0, print_attr_num }, /*86*/
    462      { "NAS-Port-Id",                     NULL, 0, 0, print_attr_string },
    463      { "Framed-Pool",                     NULL, 0, 0, print_attr_string },
    464      { "CUI",                             NULL, 0, 0, print_attr_string },
    465      { "Tunnel-Client-Auth-ID",           NULL, 0, 0, print_attr_string },
    466      { "Tunnel-Server-Auth-ID",           NULL, 0, 0, print_attr_string },
    467      { "Unassigned",                      NULL, 0, 0, NULL }, /*92*/
    468      { "Unassigned",                      NULL, 0, 0, NULL }  /*93*/
    469   };
    470 
    471 
    472 /*****************************/
    473 /* Print an attribute string */
    474 /* value pointed by 'data'   */
    475 /* and 'length' size.        */
    476 /*****************************/
    477 /* Returns nothing.          */
    478 /*****************************/
    479 static void
    480 print_attr_string(netdissect_options *ndo,
    481                   register u_char *data, u_int length, u_short attr_code)
    482 {
    483    register u_int i;
    484 
    485    ND_TCHECK2(data[0],length);
    486 
    487    switch(attr_code)
    488    {
    489       case TUNNEL_PASS:
    490            if (length < 3)
    491            {
    492               ND_PRINT((ndo, "%s", tstr));
    493               return;
    494            }
    495            if (*data && (*data <=0x1F) )
    496               ND_PRINT((ndo, "Tag[%u] ", *data));
    497            else
    498               ND_PRINT((ndo, "Tag[Unused] "));
    499            data++;
    500            length--;
    501            ND_PRINT((ndo, "Salt %u ", EXTRACT_16BITS(data)));
    502            data+=2;
    503            length-=2;
    504         break;
    505       case TUNNEL_CLIENT_END:
    506       case TUNNEL_SERVER_END:
    507       case TUNNEL_PRIV_GROUP:
    508       case TUNNEL_ASSIGN_ID:
    509       case TUNNEL_CLIENT_AUTH:
    510       case TUNNEL_SERVER_AUTH:
    511            if (*data <= 0x1F)
    512            {
    513               if (length < 1)
    514               {
    515                  ND_PRINT((ndo, "%s", tstr));
    516                  return;
    517               }
    518               if (*data)
    519                 ND_PRINT((ndo, "Tag[%u] ", *data));
    520               else
    521                 ND_PRINT((ndo, "Tag[Unused] "));
    522               data++;
    523               length--;
    524            }
    525         break;
    526       case EGRESS_VLAN_NAME:
    527            ND_PRINT((ndo, "%s (0x%02x) ",
    528                   tok2str(rfc4675_tagged,"Unknown tag",*data),
    529                   *data));
    530            data++;
    531            length--;
    532         break;
    533    }
    534 
    535    for (i=0; *data && i < length ; i++, data++)
    536        ND_PRINT((ndo, "%c", (*data < 32 || *data > 128) ? '.' : *data));
    537 
    538    return;
    539 
    540    trunc:
    541       ND_PRINT((ndo, "%s", tstr));
    542 }
    543 
    544 /*
    545  * print vendor specific attributes
    546  */
    547 static void
    548 print_vendor_attr(netdissect_options *ndo,
    549                   register u_char *data, u_int length, u_short attr_code _U_)
    550 {
    551     u_int idx;
    552     u_int vendor_id;
    553     u_int vendor_type;
    554     u_int vendor_length;
    555 
    556     if (length < 4)
    557         goto trunc;
    558     ND_TCHECK2(*data, 4);
    559     vendor_id = EXTRACT_32BITS(data);
    560     data+=4;
    561     length-=4;
    562 
    563     ND_PRINT((ndo, "Vendor: %s (%u)",
    564            tok2str(smi_values,"Unknown",vendor_id),
    565            vendor_id));
    566 
    567     while (length >= 2) {
    568 	ND_TCHECK2(*data, 2);
    569 
    570         vendor_type = *(data);
    571         vendor_length = *(data+1);
    572 
    573         if (vendor_length < 2)
    574         {
    575             ND_PRINT((ndo, "\n\t    Vendor Attribute: %u, Length: %u (bogus, must be >= 2)",
    576                    vendor_type,
    577                    vendor_length));
    578             return;
    579         }
    580         if (vendor_length > length)
    581         {
    582             ND_PRINT((ndo, "\n\t    Vendor Attribute: %u, Length: %u (bogus, goes past end of vendor-specific attribute)",
    583                    vendor_type,
    584                    vendor_length));
    585             return;
    586         }
    587         data+=2;
    588         vendor_length-=2;
    589         length-=2;
    590 	ND_TCHECK2(*data, vendor_length);
    591 
    592         ND_PRINT((ndo, "\n\t    Vendor Attribute: %u, Length: %u, Value: ",
    593                vendor_type,
    594                vendor_length));
    595         for (idx = 0; idx < vendor_length ; idx++, data++)
    596             ND_PRINT((ndo, "%c", (*data < 32 || *data > 128) ? '.' : *data));
    597         length-=vendor_length;
    598     }
    599     return;
    600 
    601    trunc:
    602      ND_PRINT((ndo, "%s", tstr));
    603 }
    604 
    605 /******************************/
    606 /* Print an attribute numeric */
    607 /* value pointed by 'data'    */
    608 /* and 'length' size.         */
    609 /******************************/
    610 /* Returns nothing.           */
    611 /******************************/
    612 static void
    613 print_attr_num(netdissect_options *ndo,
    614                register u_char *data, u_int length, u_short attr_code)
    615 {
    616    uint32_t timeout;
    617 
    618    if (length != 4)
    619    {
    620        ND_PRINT((ndo, "ERROR: length %u != 4", length));
    621        return;
    622    }
    623 
    624    ND_TCHECK2(data[0],4);
    625                           /* This attribute has standard values */
    626    if (attr_type[attr_code].siz_subtypes)
    627    {
    628       static const char **table;
    629       uint32_t data_value;
    630       table = attr_type[attr_code].subtypes;
    631 
    632       if ( (attr_code == TUNNEL_TYPE) || (attr_code == TUNNEL_MEDIUM) )
    633       {
    634          if (!*data)
    635             ND_PRINT((ndo, "Tag[Unused] "));
    636          else
    637             ND_PRINT((ndo, "Tag[%d] ", *data));
    638          data++;
    639          data_value = EXTRACT_24BITS(data);
    640       }
    641       else
    642       {
    643          data_value = EXTRACT_32BITS(data);
    644       }
    645       if ( data_value <= (uint32_t)(attr_type[attr_code].siz_subtypes - 1 +
    646             attr_type[attr_code].first_subtype) &&
    647 	   data_value >= attr_type[attr_code].first_subtype )
    648          ND_PRINT((ndo, "%s", table[data_value]));
    649       else
    650          ND_PRINT((ndo, "#%u", data_value));
    651    }
    652    else
    653    {
    654       switch(attr_code) /* Be aware of special cases... */
    655       {
    656         case FRM_IPX:
    657              if (EXTRACT_32BITS( data) == 0xFFFFFFFE )
    658                 ND_PRINT((ndo, "NAS Select"));
    659              else
    660                 ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
    661           break;
    662 
    663         case SESSION_TIMEOUT:
    664         case IDLE_TIMEOUT:
    665         case ACCT_DELAY:
    666         case ACCT_SESSION_TIME:
    667         case ACCT_INT_INTERVAL:
    668              timeout = EXTRACT_32BITS( data);
    669              if ( timeout < 60 )
    670                 ND_PRINT((ndo,  "%02d secs", timeout));
    671              else
    672              {
    673                 if ( timeout < 3600 )
    674                    ND_PRINT((ndo,  "%02d:%02d min",
    675                           timeout / 60, timeout % 60));
    676                 else
    677                    ND_PRINT((ndo, "%02d:%02d:%02d hours",
    678                           timeout / 3600, (timeout % 3600) / 60,
    679                           timeout % 60));
    680              }
    681           break;
    682 
    683         case FRM_ATALK_LINK:
    684              if (EXTRACT_32BITS(data) )
    685                 ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
    686              else
    687                 ND_PRINT((ndo, "Unnumbered"));
    688           break;
    689 
    690         case FRM_ATALK_NETWORK:
    691              if (EXTRACT_32BITS(data) )
    692                 ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
    693              else
    694                 ND_PRINT((ndo, "NAS assigned"));
    695           break;
    696 
    697         case TUNNEL_PREFERENCE:
    698             if (*data)
    699                ND_PRINT((ndo, "Tag[%d] ", *data));
    700             else
    701                ND_PRINT((ndo, "Tag[Unused] "));
    702             data++;
    703             ND_PRINT((ndo, "%d", EXTRACT_24BITS(data)));
    704           break;
    705 
    706         case EGRESS_VLAN_ID:
    707             ND_PRINT((ndo, "%s (0x%02x) ",
    708                    tok2str(rfc4675_tagged,"Unknown tag",*data),
    709                    *data));
    710             data++;
    711             ND_PRINT((ndo, "%d", EXTRACT_24BITS(data)));
    712           break;
    713 
    714         default:
    715              ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
    716           break;
    717 
    718       } /* switch */
    719 
    720    } /* if-else */
    721 
    722    return;
    723 
    724    trunc:
    725      ND_PRINT((ndo, "%s", tstr));
    726 }
    727 
    728 /*****************************/
    729 /* Print an attribute IPv4   */
    730 /* address value pointed by  */
    731 /* 'data' and 'length' size. */
    732 /*****************************/
    733 /* Returns nothing.          */
    734 /*****************************/
    735 static void
    736 print_attr_address(netdissect_options *ndo,
    737                    register u_char *data, u_int length, u_short attr_code)
    738 {
    739    if (length != 4)
    740    {
    741        ND_PRINT((ndo, "ERROR: length %u != 4", length));
    742        return;
    743    }
    744 
    745    ND_TCHECK2(data[0],4);
    746 
    747    switch(attr_code)
    748    {
    749       case FRM_IPADDR:
    750       case LOG_IPHOST:
    751            if (EXTRACT_32BITS(data) == 0xFFFFFFFF )
    752               ND_PRINT((ndo, "User Selected"));
    753            else
    754               if (EXTRACT_32BITS(data) == 0xFFFFFFFE )
    755                  ND_PRINT((ndo, "NAS Select"));
    756               else
    757                  ND_PRINT((ndo, "%s",ipaddr_string(ndo, data)));
    758       break;
    759 
    760       default:
    761           ND_PRINT((ndo, "%s", ipaddr_string(ndo, data)));
    762       break;
    763    }
    764 
    765    return;
    766 
    767    trunc:
    768      ND_PRINT((ndo, "%s", tstr));
    769 }
    770 
    771 /*************************************/
    772 /* Print an attribute of 'secs since */
    773 /* January 1, 1970 00:00 UTC' value  */
    774 /* pointed by 'data' and 'length'    */
    775 /* size.                             */
    776 /*************************************/
    777 /* Returns nothing.                  */
    778 /*************************************/
    779 static void
    780 print_attr_time(netdissect_options *ndo,
    781                 register u_char *data, u_int length, u_short attr_code _U_)
    782 {
    783    time_t attr_time;
    784    char string[26];
    785 
    786    if (length != 4)
    787    {
    788        ND_PRINT((ndo, "ERROR: length %u != 4", length));
    789        return;
    790    }
    791 
    792    ND_TCHECK2(data[0],4);
    793 
    794    attr_time = EXTRACT_32BITS(data);
    795    strlcpy(string, ctime(&attr_time), sizeof(string));
    796    /* Get rid of the newline */
    797    string[24] = '\0';
    798    ND_PRINT((ndo, "%.24s", string));
    799    return;
    800 
    801    trunc:
    802      ND_PRINT((ndo, "%s", tstr));
    803 }
    804 
    805 /***********************************/
    806 /* Print an attribute of 'strange' */
    807 /* data format pointed by 'data'   */
    808 /* and 'length' size.              */
    809 /***********************************/
    810 /* Returns nothing.                */
    811 /***********************************/
    812 static void
    813 print_attr_strange(netdissect_options *ndo,
    814                    register u_char *data, u_int length, u_short attr_code)
    815 {
    816    u_short len_data;
    817 
    818    switch(attr_code)
    819    {
    820       case ARAP_PASS:
    821            if (length != 16)
    822            {
    823                ND_PRINT((ndo, "ERROR: length %u != 16", length));
    824                return;
    825            }
    826            ND_PRINT((ndo, "User_challenge ("));
    827            ND_TCHECK2(data[0],8);
    828            len_data = 8;
    829            PRINT_HEX(len_data, data);
    830            ND_PRINT((ndo, ") User_resp("));
    831            ND_TCHECK2(data[0],8);
    832            len_data = 8;
    833            PRINT_HEX(len_data, data);
    834            ND_PRINT((ndo, ")"));
    835         break;
    836 
    837       case ARAP_FEATURES:
    838            if (length != 14)
    839            {
    840                ND_PRINT((ndo, "ERROR: length %u != 14", length));
    841                return;
    842            }
    843            ND_TCHECK2(data[0],1);
    844            if (*data)
    845               ND_PRINT((ndo, "User can change password"));
    846            else
    847               ND_PRINT((ndo, "User cannot change password"));
    848            data++;
    849            ND_TCHECK2(data[0],1);
    850            ND_PRINT((ndo, ", Min password length: %d", *data));
    851            data++;
    852            ND_PRINT((ndo, ", created at: "));
    853            ND_TCHECK2(data[0],4);
    854            len_data = 4;
    855            PRINT_HEX(len_data, data);
    856            ND_PRINT((ndo, ", expires in: "));
    857            ND_TCHECK2(data[0],4);
    858            len_data = 4;
    859            PRINT_HEX(len_data, data);
    860            ND_PRINT((ndo, ", Current Time: "));
    861            ND_TCHECK2(data[0],4);
    862            len_data = 4;
    863            PRINT_HEX(len_data, data);
    864         break;
    865 
    866       case ARAP_CHALLENGE_RESP:
    867            if (length < 8)
    868            {
    869                ND_PRINT((ndo, "ERROR: length %u != 8", length));
    870                return;
    871            }
    872            ND_TCHECK2(data[0],8);
    873            len_data = 8;
    874            PRINT_HEX(len_data, data);
    875         break;
    876    }
    877    return;
    878 
    879    trunc:
    880      ND_PRINT((ndo, "%s", tstr));
    881 }
    882 
    883 static void
    884 radius_attrs_print(netdissect_options *ndo,
    885                    register const u_char *attr, u_int length)
    886 {
    887    register const struct radius_attr *rad_attr = (struct radius_attr *)attr;
    888    const char *attr_string;
    889 
    890    while (length > 0)
    891    {
    892      if (length < 2)
    893         goto trunc;
    894      ND_TCHECK(*rad_attr);
    895 
    896      if (rad_attr->type > 0 && rad_attr->type < TAM_SIZE(attr_type))
    897 	attr_string = attr_type[rad_attr->type].name;
    898      else
    899 	attr_string = "Unknown";
    900      if (rad_attr->len < 2)
    901      {
    902 	ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u (bogus, must be >= 2)",
    903                attr_string,
    904                rad_attr->type,
    905                rad_attr->len));
    906 	return;
    907      }
    908      if (rad_attr->len > length)
    909      {
    910 	ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u (bogus, goes past end of packet)",
    911                attr_string,
    912                rad_attr->type,
    913                rad_attr->len));
    914         return;
    915      }
    916      ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u, Value: ",
    917             attr_string,
    918             rad_attr->type,
    919             rad_attr->len));
    920 
    921      if (rad_attr->type < TAM_SIZE(attr_type))
    922      {
    923          if (rad_attr->len > 2)
    924          {
    925              if ( attr_type[rad_attr->type].print_func )
    926                  (*attr_type[rad_attr->type].print_func)(
    927                      ndo, ((u_char *)(rad_attr+1)),
    928                      rad_attr->len - 2, rad_attr->type);
    929          }
    930      }
    931      /* do we also want to see a hex dump ? */
    932      if (ndo->ndo_vflag> 1)
    933          print_unknown_data(ndo, (u_char *)rad_attr+2, "\n\t    ", (rad_attr->len)-2);
    934 
    935      length-=(rad_attr->len);
    936      rad_attr = (struct radius_attr *)( ((char *)(rad_attr))+rad_attr->len);
    937    }
    938    return;
    939 
    940 trunc:
    941    ND_PRINT((ndo, "%s", tstr));
    942 }
    943 
    944 void
    945 radius_print(netdissect_options *ndo,
    946              const u_char *dat, u_int length)
    947 {
    948    register const struct radius_hdr *rad;
    949    u_int len, auth_idx;
    950 
    951    ND_TCHECK2(*dat, MIN_RADIUS_LEN);
    952    rad = (struct radius_hdr *)dat;
    953    len = EXTRACT_16BITS(&rad->len);
    954 
    955    if (len < MIN_RADIUS_LEN)
    956    {
    957 	  ND_PRINT((ndo, "%s", tstr));
    958 	  return;
    959    }
    960 
    961    if (len > length)
    962 	  len = length;
    963 
    964    if (ndo->ndo_vflag < 1) {
    965        ND_PRINT((ndo, "RADIUS, %s (%u), id: 0x%02x length: %u",
    966               tok2str(radius_command_values,"Unknown Command",rad->code),
    967               rad->code,
    968               rad->id,
    969               len));
    970        return;
    971    }
    972    else {
    973        ND_PRINT((ndo, "RADIUS, length: %u\n\t%s (%u), id: 0x%02x, Authenticator: ",
    974               len,
    975               tok2str(radius_command_values,"Unknown Command",rad->code),
    976               rad->code,
    977               rad->id));
    978 
    979        for(auth_idx=0; auth_idx < 16; auth_idx++)
    980             ND_PRINT((ndo, "%02x", rad->auth[auth_idx]));
    981    }
    982 
    983    if (len > MIN_RADIUS_LEN)
    984       radius_attrs_print(ndo, dat + MIN_RADIUS_LEN, len - MIN_RADIUS_LEN);
    985    return;
    986 
    987 trunc:
    988    ND_PRINT((ndo, "%s", tstr));
    989 }
    990