c6046b96fbeb992e41afef15762948e46d7f63c5
[metze/wireshark/wip.git] / packet-bootp.c
1 /* packet-bootp.c
2  * Routines for BOOTP/DHCP packet disassembly
3  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
4  *
5  * $Id: packet-bootp.c,v 1.16 1999/03/23 03:14:35 gram Exp $
6  *
7  * The information used comes from:
8  * RFC 2132: DHCP Options and BOOTP Vendor Extensions
9  * RFC 1542: Clarifications and Extensions for the Bootstrap Protocol
10  * RFC 2131: Dynamic Host Configuration Protocol
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@unicom.net>
14  * Copyright 1998 Gerald Combs
15  *
16  * 
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * 
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #include <glib.h>
41 #include "packet.h"
42
43 enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
44         time_in_secs,
45         val_u_byte, val_u_short, val_u_long,
46         val_s_long };
47
48 struct opt_info {
49         char    *text;
50         enum field_type ftype;
51 };
52
53 #define NUM_OPT_INFOS 77
54
55 /* returns the number of bytes consumed by this option */
56 static int
57 bootp_option(const u_char *pd, proto_tree *bp_tree, int voff, int eoff)
58 {
59         char                    *text;
60         enum field_type ftype;
61         u_char                  code = pd[voff];
62         int                             vlen = pd[voff+1];
63         u_char                  byte;
64         int                             i, consumed = vlen + 2;
65         u_long                  time_secs;
66         proto_tree              *v_tree;
67         proto_item              *vti;
68
69         static const char       *opt53_text[] = {
70                 "Unknown Message Type",
71                 "Discover",
72                 "Offer",
73                 "Request",
74                 "Decline",
75                 "ACK",
76                 "NAK",
77                 "Release",
78                 "Inform"
79         };
80         static const value_string nbnt_vals[] = {
81             {0x1,   "B-node" },
82             {0x2,   "P-node" },
83             {0x4,   "M-node" },
84             {0x8,   "H-node" },
85             {0,     NULL     } };
86
87         static struct opt_info opt[] = {
88                 /*   0 */ { "Padding",                                                          none },
89                 /*   1 */ { "Subnet Mask",                                                      ipv4 },
90                 /*   2 */ { "Time Offset",                                                      val_s_long },
91                 /*   3 */ { "Router",                                                           ipv4 },
92                 /*   4 */ { "Time Server",                                                      ipv4 },
93                 /*   5 */ { "Name Server",                                                      ipv4 },
94                 /*   6 */ { "Domain Name Server",                                       ipv4 },
95                 /*   7 */ { "Log Server",                                                       ipv4 },
96                 /*   8 */ { "Cookie Server",                                            ipv4 },
97                 /*   9 */ { "LPR Server",                                                       ipv4 },
98                 /*  10 */ { "Impress Server",                                           ipv4 },
99                 /*  11 */ { "Resource Location Server",                         ipv4 },
100                 /*  12 */ { "Host Name",                                                        string },
101                 /*  13 */ { "Boot File Size",                                           val_u_short },
102                 /*  14 */ { "Merit Dump File",                                          string },
103                 /*  15 */ { "Domain Name",                                                      string },
104                 /*  16 */ { "Swap Server",                                                      ipv4 },
105                 /*  17 */ { "Root Path",                                                        string },
106                 /*  18 */ { "Extensions Path",                                          string },
107                 /*  19 */ { "IP Forwarding",                                            toggle },
108                 /*  20 */ { "Non-Local Source Routing",                         toggle },
109                 /*  21 */ { "Policy Filter",                                            special },
110                 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short },
111                 /*  23 */ { "Default IP Time-to-Live",                          val_u_byte },
112                 /*  24 */ { "Path MTU Aging Timeout",                           time_in_secs },
113                 /*  25 */ { "Path MTU Plateau Table",                           val_u_short },
114                 /*  26 */ { "Interface MTU",                                            val_u_short },
115                 /*  27 */ { "All Subnets are Local",                            yes_no },
116                 /*  28 */ { "Broadcast Address",                                        ipv4 },
117                 /*  29 */ { "Perform Mask Discovery",                           toggle },
118                 /*  30 */ { "Mask Supplier",                                            yes_no },
119                 /*  31 */ { "Perform Router Discover",                          toggle },
120                 /*  32 */ { "Router Solicitation Address",                      ipv4 },
121                 /*  33 */ { "Static Route",                                                     special },
122                 /*  34 */ { "Trailer Encapsulation",                            toggle },
123                 /*  35 */ { "ARP Cache Timeout",                                        time_in_secs },
124                 /*  36 */ { "Ethernet Encapsulation",                           toggle },
125                 /*  37 */ { "TCP Default TTL",                                          val_u_byte },
126                 /*  38 */ { "TCP Keepalive Interval",                           time_in_secs },
127                 /*  39 */ { "TCP Keepalive Garbage",                            toggle },
128                 /*  40 */ { "Network Information Service Domain",       string },
129                 /*  41 */ { "Network Information Service Servers",      ipv4 },
130                 /*  42 */ { "Network Time Protocol Servers",            ipv4 },
131                 /*  43 */ { "Vendor-Specific Information",                      special },
132                 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4 },
133                 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4 },
134                 /*  46 */ { "NetBIOS over TCP/IP Node Type",            special },
135                 /*  47 */ { "NetBIOS over TCP/IP Scope",                        string },
136                 /*  48 */ { "X Window System Font Server",                      ipv4 },
137                 /*  49 */ { "X Window System Display Manager",          ipv4 },
138                 /*  50 */ { "Requested IP Address",                                     ipv4 },
139                 /*  51 */ { "IP Address Lease Time",                            time_in_secs },
140                 /*  52 */ { "Option Overload",                                          special },
141                 /*  53 */ { "DHCP Message Type",                                        special },
142                 /*  54 */ { "Server Identifier",                                        ipv4 },
143                 /*  55 */ { "Parameter Request List",                           special },
144                 /*  56 */ { "Message",                                                          string },
145                 /*  57 */ { "Maximum DHCP Message Size",                        val_u_short },
146                 /*  58 */ { "Renewal Time Value",                                       time_in_secs },
147                 /*  59 */ { "Rebinding Time Value",                                     time_in_secs },
148                 /*  60 */ { "Vendor class identifier",                          opaque },
149                 /*  61 */ { "Client identifier",                                        special },
150                 /*  64 */ { "Network Information Service+ Domain",      string },
151                 /*  65 */ { "Network Information Service+ Servers",     ipv4 },
152                 /*  66 */ { "TFTP Server Name",                                         string },
153                 /*  67 */ { "Bootfile name",                                            string },
154                 /*  68 */ { "Mobile IP Home Agent",                                     ipv4 },
155                 /*  69 */ { "SMTP Server",                                                      ipv4 },
156                 /*  70 */ { "POP3 Server",                                                      ipv4 },
157                 /*  71 */ { "NNTP Server",                                                      ipv4 },
158                 /*  72 */ { "Default WWW Server",                                       ipv4 },
159                 /*  73 */ { "Default Finger Server",                            ipv4 },
160                 /*  74 */ { "Default IRC Server",                                       ipv4 },
161                 /*  75 */ { "StreetTalk Server",                                        ipv4 },
162                 /*  76 */ { "StreetTalk Directory Assistance Server", ipv4 }
163         };
164
165         text = opt[code].text;
166         /* Special cases */
167         switch (code) {
168                 /* Padding */
169                 case 0:
170                         /* check how much padding we have */
171                         for (i = voff + 1; i < eoff; i++ ) {
172                                 if (pd[i] != 0) {
173                                         break;
174                                 }
175                         }
176                         i = i - voff;
177                         proto_tree_add_item(bp_tree, voff, i, "Padding");
178                         consumed = i;
179                         return consumed;
180
181                 /* Policy Filter */
182                 case 21:
183                         /* one IP address pair */
184                         if (vlen == 8) {
185                                 proto_tree_add_item(bp_tree, voff, consumed,
186                                         "Option %d: %s = %s/%s", code, text,
187                                         ip_to_str((guint8*)&pd[voff+2]),
188                                         ip_to_str((guint8*)&pd[voff+6]));
189                         }
190                         /* > 1 IP address pair. Let's make a sub-tree */
191                         else {
192
193                                 vti = proto_tree_add_item(bp_tree, voff,
194                                         consumed, "Option %d: %s", code, text);
195                                 v_tree = proto_tree_new();
196                                 proto_item_add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
197                                 for (i = voff + 2; i < voff + consumed; i += 8) {
198                                         proto_tree_add_item(v_tree, i, 8, "IP Address/Mask: %s/%s",
199                                                 ip_to_str((guint8*)&pd[i]),
200                                                 ip_to_str((guint8*)&pd[i+4]));
201                                 }
202                         }
203                         break;
204
205                 /* Static Route */
206                 case 33:
207                         /* one IP address pair */
208                         if (vlen == 8) {
209                                 proto_tree_add_item(bp_tree, voff, consumed,
210                                         "Option %d: %s = %s/%s", code, text,
211                                         ip_to_str((guint8*)&pd[voff+2]),
212                                         ip_to_str((guint8*)&pd[voff+6]));
213                         }
214                         /* > 1 IP address pair. Let's make a sub-tree */
215                         else {
216
217                                 vti = proto_tree_add_item(bp_tree, voff,
218                                         consumed, "Option %d: %s", code, text);
219                                 v_tree = proto_tree_new();
220                                 proto_item_add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
221                                 for (i = voff + 2; i < voff + consumed; i += 8) {
222                                         proto_tree_add_item(v_tree, i, 8,
223                                                 "Destination IP Address/Router: %s/%s",
224                                                 ip_to_str((guint8*)&pd[i]),
225                                                 ip_to_str((guint8*)&pd[i+4]));
226                                 }
227                         }
228                         break;
229
230                 /* Vendor-Specific Info */
231                 case 43:
232                         proto_tree_add_item(bp_tree, voff, consumed,
233                                         "Option %d: %s", code, text);
234                         break;
235
236                 /* NetBIOS-over-TCP/IP Node Type */
237                 case 46:
238                         byte = pd[voff+2];
239                         proto_tree_add_item(bp_tree, voff, consumed,
240                                         "Option %d: %s = %s", code, text,
241                                         val_to_str(byte, nbnt_vals,
242                                             "Unknown (0x%02x)"));
243                         break;
244                                 
245                 /* DHCP Message Type */
246                 case 53:
247                         byte = pd[voff+2];
248                         if (byte > 0 && byte < 9) {
249                                 i = byte;
250                         }
251                         else {
252                                 i = 0;
253                         }
254                         proto_tree_add_item(bp_tree, voff, 3, "Option %d: %s = DHCP %s",
255                                 code, text, opt53_text[i]);
256                         break;
257
258                 /* Parameter Request List */
259                 case 55:
260                         vti = proto_tree_add_item(bp_tree, voff,
261                                 vlen + 2, "Option %d: %s", code, text);
262                         v_tree = proto_tree_new();
263                         proto_item_add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
264                         for (i = 0; i < vlen; i++) {
265                                 byte = pd[voff+2+i];
266                                 if (byte < NUM_OPT_INFOS) {
267                                         proto_tree_add_item(v_tree, voff+2+i, 1, "%d = %s",
268                                                         byte, opt[byte].text);
269                                 }
270                                 else {
271                                         proto_tree_add_item(vti, voff+2+i, 1,
272                                                 "Unknown Option Code: %d", byte);
273                                 }
274                         }
275                         break;
276
277                 /* Client Identifier */
278                 case 61:
279                         /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
280                                 guess that the first is the hwtype, and the last 6 are
281                                 the hw addr */
282                         if (vlen == 7) {
283                                 vti = proto_tree_add_item(bp_tree, voff,
284                                         consumed, "Option %d: %s", code, text);
285                                 v_tree = proto_tree_new();
286                                 proto_item_add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
287                                 proto_tree_add_item(v_tree, voff+2, 1,
288                                         "Hardware type: %s",
289                                         arphrdtype_to_str(pd[voff+2],
290                                                 "Unknown (0x%02x)"));
291                                 proto_tree_add_item(v_tree, voff+3, 6,
292                                         "Client hardware address: %s",
293                                         arphrdaddr_to_str((guint8*)&pd[voff+3],
294                                                 6, pd[voff+2]));
295                         }
296                         /* otherwise, it's opaque data */
297                         else {
298                                 proto_tree_add_item(bp_tree, voff, consumed,
299                                         "Option %d: %s (%d bytes)", code, text, vlen);
300                         }
301                         break;
302
303                 /* End Option */
304                 case 255:
305                         proto_tree_add_item(bp_tree, voff, 1, "End Option");
306                         consumed = 1;
307                         return consumed;
308
309                 default:
310                         /* nothing */
311                         break;
312         }
313
314         /* Normal cases */
315         if (code < NUM_OPT_INFOS) {
316                 text = opt[code].text;
317                 ftype = opt[code].ftype;
318
319                 switch (ftype) {
320                         case special:
321                                 return consumed;
322
323                         case ipv4:
324                                 /* one IP address */
325                                 if (vlen == 4) {
326                                         proto_tree_add_item(bp_tree, voff, consumed,
327                                                 "Option %d: %s = %s", code, text,
328                                                 ip_to_str((guint8*)&pd[voff+2]));
329                                 }
330                                 /* > 1 IP addresses. Let's make a sub-tree */
331                                 else {
332
333                                         vti = proto_tree_add_item(bp_tree, voff,
334                                                 consumed, "Option %d: %s", code, text);
335                                         v_tree = proto_tree_new();
336                                         proto_item_add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
337                                         for (i = voff + 2; i < voff + consumed; i += 4) {
338                                                 proto_tree_add_item(v_tree, i, 4, "IP Address: %s",
339                                                         ip_to_str((guint8*)&pd[i]));
340                                         }
341                                 }
342                                 break;
343
344                         case string:
345                                 /* Fix for non null-terminated string supplied by
346                                  * John Lines <John.Lines@aeat.co.uk>
347                                  */
348                                 proto_tree_add_item(bp_tree, voff, consumed,
349                                                 "Option %d: %s = %.*s", code, text, vlen, &pd[voff+2]);
350                                 break;
351
352                         case opaque:
353                                 proto_tree_add_item(bp_tree, voff, consumed,
354                                                 "Option %d: %s (%d bytes)",
355                                                 code, text, vlen);
356                                 break;
357
358                         case val_u_short:
359                                 /* one IP address */
360                                 if (vlen == 2) {
361                                         proto_tree_add_item(bp_tree, voff, consumed,
362                                                         "Option %d: %s = %d", code, text,
363                                                         pntohs(&pd[voff+2]));
364                                 }
365                                 /* > 1 u_short */
366                                 else {
367                                         vti = proto_tree_add_item(bp_tree, voff,
368                                                 consumed, "Option %d: %s", code, text);
369                                         v_tree = proto_tree_new();
370                                         proto_item_add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
371                                         for (i = voff + 2; i < voff + consumed; i += 2) {
372                                                 proto_tree_add_item(v_tree, i, 4, "Value: %d",
373                                                         pntohs(&pd[i]));
374                                         }
375                                 }
376                                 break;
377
378                         case val_u_long:
379                                 proto_tree_add_item(bp_tree, voff, consumed,
380                                                 "Option %d: %s = %d", code, text,
381                                                 pntohl(&pd[voff+2]));
382                                 break;
383
384                         case val_u_byte:
385                                 proto_tree_add_item(bp_tree, voff, consumed,
386                                                 "Option %d: %s = %d", code, text, pd[voff+2]);
387                                 break;
388
389                         case toggle:
390                                 i = pd[voff+2];
391                                 if (i != 0 && i != 1) {
392                                         proto_tree_add_item(bp_tree, voff, consumed,
393                                                         "Option %d: %s = Invalid Value %d", code, text,
394                                                         pd[voff+2]);
395                                 }
396                                 else {
397                                         proto_tree_add_item(bp_tree, voff, consumed,
398                                                         "Option %d: %s = %s", code, text,
399                                                         pd[voff+2] == 0 ? "Disabled" : "Enabled");
400                                 }
401                                 break;
402
403                         case yes_no:
404                                 i = pd[voff+2];
405                                 if (i != 0 && i != 1) {
406                                         proto_tree_add_item(bp_tree, voff, consumed,
407                                                         "Option %d: %s = Invalid Value %d", code, text,
408                                                         pd[voff+2]);
409                                 }
410                                 else {
411                                         proto_tree_add_item(bp_tree, voff, consumed,
412                                                         "Option %d: %s = %s", code, text,
413                                                         pd[voff+2] == 0 ? "No" : "Yes");
414                                 }
415                                 break;
416
417                         case time_in_secs:
418                                 time_secs = pntohl(&pd[voff+2]);
419                                 proto_tree_add_item(bp_tree, voff, consumed,
420                                         "Option %d: %s = %s", code, text,
421                                         ((time_secs == 0xffffffff) ?
422                                             "infinity" :
423                                             time_secs_to_str(time_secs)));
424                                 break;
425
426                         default:
427                                 proto_tree_add_item(bp_tree, voff, consumed,
428                                                 "Option %d: %s (%d bytes)", code, text, vlen);
429                 }
430         }
431         else {
432                 proto_tree_add_item(bp_tree, voff, consumed,
433                                 "Unknown Option Code: %d (%d bytes)", code, vlen);
434         }
435
436         return consumed;
437 }
438
439 void
440 dissect_bootp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
441 {
442         proto_tree      *bp_tree;
443         proto_item      *ti;
444         int                     voff, eoff; /* vender offset, end offset */
445
446         if (check_col(fd, COL_PROTOCOL))
447                 col_add_str(fd, COL_PROTOCOL, "BOOTP");
448
449         if (check_col(fd, COL_INFO)) {
450                 if (pd[offset] == 1) {
451                         col_add_fstr(fd, COL_INFO, "Boot Request from %s",
452                                 arphrdaddr_to_str((guint8*)&pd[offset+28],
453                                         pd[offset+2], pd[offset+1]));
454                 }
455                 else {
456                         col_add_str(fd, COL_INFO, "Boot Reply");
457                 }
458         }
459
460         if (tree) {
461                 ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
462                   "Bootstrap Protocol");
463                 bp_tree = proto_tree_new();
464                 proto_item_add_subtree(ti, bp_tree, ETT_BOOTP);
465
466                 proto_tree_add_item(bp_tree, offset, 1, pd[offset] == 1 ?
467                         "Boot Request" : "Boot Reply");
468                 proto_tree_add_item(bp_tree, offset + 1, 1,
469                         "Hardware type: %s",
470                         arphrdtype_to_str(pd[offset+1], "Unknown (0x%02x)"));
471                 proto_tree_add_item(bp_tree, offset + 2, 1,
472                         "Hardware address length: %d", pd[offset+2]);
473                 proto_tree_add_item(bp_tree, offset + 3, 1,
474                         "Hops: %d", pd[offset+3]);
475                 proto_tree_add_item(bp_tree, offset + 4, 4,
476                         "Transaction ID: 0x%08x", pntohl(&pd[offset+4]));
477                 proto_tree_add_item(bp_tree, offset + 8, 2,
478                         "Seconds elapsed: %d", pntohs(&pd[offset+8]));
479                 proto_tree_add_item(bp_tree, offset + 10, 2,
480                         "Broadcast flag: %d", pd[offset+10] & 1);
481                 proto_tree_add_item(bp_tree, offset + 12, 4,
482                         "Client IP address: %s", ip_to_str((guint8*)&pd[offset+12]));
483                 proto_tree_add_item(bp_tree, offset + 16, 4,
484                         "Your (client) IP address: %s", ip_to_str((guint8*)&pd[offset+16]));
485                 proto_tree_add_item(bp_tree, offset + 20, 4,
486                         "Next server IP address: %s", ip_to_str((guint8*)&pd[offset+20]));
487                 proto_tree_add_item(bp_tree, offset + 24, 4,
488                         "Relay agent IP address: %s", ip_to_str((guint8*)&pd[offset+24]));
489
490                 proto_tree_add_item(bp_tree, offset + 28, pd[offset+2],
491                         "Client hardware address: %s",
492                         arphrdaddr_to_str((guint8*)&pd[offset+28],
493                                 pd[offset+2], pd[offset+1]));
494
495                 /* The server host name is optional */
496                 if (pd[offset+44]) {
497                         proto_tree_add_item(bp_tree, offset + 44, 64,
498                                 "Server host name: %s", &pd[offset+44]);
499                 }
500                 else {
501                         proto_tree_add_item(bp_tree, offset + 44, 64,
502                                 "Server host name not given");
503                 }
504
505                 /* Boot file */
506                 if (pd[offset+108]) {
507                         proto_tree_add_item(bp_tree, offset + 108, 128,
508                                 "Boot file name: %s", &pd[offset+108]);
509                 }
510                 else {
511                         proto_tree_add_item(bp_tree, offset + 108, 128,
512                                 "Boot file name not given");
513                 }
514
515                 if (pntohl(&pd[offset+236]) == 0x63825363) {
516                         proto_tree_add_item(bp_tree, offset + 236, 4,
517                                 "Magic cookie: (OK)");
518                 }
519                 else {
520                         proto_tree_add_item(bp_tree, offset + 236, 4,
521                                 "Magic cookie: %s",
522                                         ip_to_str((guint8*)&pd[offset+236]));
523                 }
524
525                 voff = offset+240;
526                 eoff = fd->cap_len;
527
528                 while (voff < eoff) {
529                         voff += bootp_option(pd, bp_tree, voff, eoff);
530                 }
531         }
532 }
533