Re-added fixes after cvs tree was changed.
[obnox/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.3 1998/09/17 03:29:26 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 #include <gtk/gtk.h>
37
38 #include <stdio.h>
39
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif
43
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
46 #endif
47
48 #include <pcap.h>
49
50 #include "packet.h"
51 #include "ethereal.h"
52 #include "etypes.h"
53
54 enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
55         val_u_byte, val_u_short, val_u_long,
56         val_s_long };
57
58 struct opt_info {
59         char    *text;
60         enum field_type ftype;
61 };
62
63 #define NUM_OPT_INFOS 77
64
65 /* returns the number of bytes consumed by this option */
66 int
67 bootp_option(const u_char *pd, GtkWidget *bp_tree, int voff, int eoff)
68 {
69         char                    *text;
70         enum field_type ftype;
71         u_char                  code = pd[voff];
72         int                             vlen = pd[voff+1];
73         int                             i, consumed;
74         GtkWidget               *vti, *v_tree;
75
76         char    *opt53_text[] = {
77                 "Unknown Message Type",
78                 "Discover",
79                 "Offer",
80                 "Request",
81                 "Decline",
82                 "ACK",
83                 "NAK",
84                 "Release",
85                 "Inform"
86         };
87
88         static struct opt_info opt[] = {
89                 /*   0 */ { "Padding",                                                          none },
90                 /*   1 */ { "Subnet Mask",                                                      ipv4 },
91                 /*   2 */ { "Time Offset",                                                      val_s_long },
92                 /*   3 */ { "Router",                                                           ipv4 },
93                 /*   4 */ { "Time Server",                                                      ipv4 },
94                 /*   5 */ { "Name Server",                                                      ipv4 },
95                 /*   6 */ { "Domain Name Server",                                       ipv4 },
96                 /*   7 */ { "Log Server",                                                       ipv4 },
97                 /*   8 */ { "Cookie Server",                                            ipv4 },
98                 /*   9 */ { "LPR Server",                                                       ipv4 },
99                 /*  10 */ { "Impress Server",                                           ipv4 },
100                 /*  11 */ { "Resource Location Server",                         ipv4 },
101                 /*  12 */ { "Host Name",                                                        string },
102                 /*  13 */ { "Boot File Size",                                           val_u_short },
103                 /*  14 */ { "Merit Dump File",                                          string },
104                 /*  15 */ { "Domain Name",                                                      string },
105                 /*  16 */ { "Swap Server",                                                      ipv4 },
106                 /*  17 */ { "Root Path",                                                        string },
107                 /*  18 */ { "Extensions Path",                                          string },
108                 /*  19 */ { "IP Forwarding",                                            toggle },
109                 /*  20 */ { "Non-Local Source Routing",                         toggle },
110                 /*  21 */ { "Policy Filter",                                            special },
111                 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short },
112                 /*  23 */ { "Default IP Time-to-Live",                          val_u_byte },
113                 /*  24 */ { "Path MTU Aging Timeout",                           val_u_long },
114                 /*  25 */ { "Path MTU Plateau Table",                           val_u_short },
115                 /*  26 */ { "Interface MTU",                                            val_u_short },
116                 /*  27 */ { "All Subnets are Local",                            yes_no },
117                 /*  28 */ { "Broadcast Address",                                        ipv4 },
118                 /*  29 */ { "Perform Mask Discovery",                           toggle },
119                 /*  30 */ { "Mask Supplier",                                            yes_no },
120                 /*  31 */ { "Perform Router Discover",                          toggle },
121                 /*  32 */ { "Router Solicitation Address",                      ipv4 },
122                 /*  33 */ { "Static Route",                                                     special },
123                 /*  34 */ { "Trailer Encapsulation",                            toggle },
124                 /*  35 */ { "ARP Cache Timeout",                                        val_u_long },
125                 /*  36 */ { "Ethernet Encapsulation",                           toggle },
126                 /*  37 */ { "TCP Default TTL",                                          val_u_byte },
127                 /*  38 */ { "TCP Keepalive Interval",                           val_u_long },
128                 /*  39 */ { "TCP Keepalive Garbage",                            toggle },
129                 /*  40 */ { "Network Information Service Domain",       string },
130                 /*  41 */ { "Network Information Service Servers",      ipv4 },
131                 /*  42 */ { "Network Time Protocol Servers",            ipv4 },
132                 /*  43 */ { "Vendor-Specific Information",                      special },
133                 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4 },
134                 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4 },
135                 /*  46 */ { "NetBIOS over TCP/IP Node Type",            special },
136                 /*  47 */ { "NetBIOS over TCP/IP Scope",                        string },
137                 /*  48 */ { "X Window System Font Server",                      ipv4 },
138                 /*  49 */ { "X Window System Display Manager",          ipv4 },
139                 /*  50 */ { "Requested IP Address",                                     ipv4 },
140                 /*  51 */ { "IP Address Lease Time",                            val_u_long },
141                 /*  52 */ { "Option Overload",                                          special },
142                 /*  53 */ { "DHCP Message Type",                                        special },
143                 /*  54 */ { "Server Identifier",                                        ipv4 },
144                 /*  55 */ { "Parameter Request List",                           opaque },
145                 /*  56 */ { "Message",                                                          string },
146                 /*  57 */ { "Maximum DHCP Message Size",                        val_u_short },
147                 /*  58 */ { "Renewal Time Value",                                       val_u_long },
148                 /*  59 */ { "Rebinding Time Value",                                     val_u_long },
149                 /*  60 */ { "Vendor class identifier",                          opaque },
150                 /*  61 */ { "Client identifier",                                        special },
151                 /*  64 */ { "Network Information Service+ Domain",      string },
152                 /*  65 */ { "Network Information Service+ Servers",     ipv4 },
153                 /*  66 */ { "TFTP Server Name",                                         string },
154                 /*  67 */ { "Bootfile name",                                            string },
155                 /*  68 */ { "Mobile IP Home Agent",                                     ipv4 },
156                 /*  69 */ { "SMTP Server",                                                      ipv4 },
157                 /*  70 */ { "POP3 Server",                                                      ipv4 },
158                 /*  71 */ { "NNTP Server",                                                      ipv4 },
159                 /*  72 */ { "Default WWW Server",                                       ipv4 },
160                 /*  73 */ { "Default Finger Server",                            ipv4 },
161                 /*  74 */ { "Default IRC Server",                                       ipv4 },
162                 /*  75 */ { "StreetTalk Server",                                        ipv4 },
163                 /*  76 */ { "StreetTalk Directory Assistance Server", ipv4 }
164         };
165
166         text = opt[code].text;
167         /* Special cases */
168         switch (code) {
169                 /* Padding */
170                 case 0:
171                         /* check how much padding we have */
172                         for (i = voff + 1; i < eoff; i++ ) {
173                                 if (pd[i] != 0) {
174                                         break;
175                                 }
176                         }
177                         i = i - voff;
178                         add_item_to_tree(bp_tree, voff, i, "Padding");
179                         consumed = i;
180                         return consumed;
181
182                 /* Policy Filter */
183                 case 21:
184                         /* one IP address pair */
185                         if (vlen == 8) {
186                                 add_item_to_tree(bp_tree, voff, consumed,
187                                         "Option %d: %s = %s/%s", code, text,
188                                         ip_to_str((guint8*)&pd[voff+2]),
189                                         ip_to_str((guint8*)&pd[voff+6]));
190                         }
191                         /* > 1 IP address pair. Let's make a sub-tree */
192                         else {
193
194                                 vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
195                                         consumed, "Option %d: %s", code, text);
196                                 v_tree = gtk_tree_new();
197                                 add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
198                                 for (i = voff + 2; i < voff + consumed; i += 8) {
199                                         add_item_to_tree(v_tree, i, 4, "IP Address/Mask: %s/%s",
200                                                 ip_to_str((guint8*)&pd[i]),
201                                                 ip_to_str((guint8*)&pd[i+4]));
202                                 }
203                         }
204
205                 /* Static Route */
206                 case 33:
207                         /* one IP address pair */
208                         if (vlen == 8) {
209                                 add_item_to_tree(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 = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
218                                         consumed, "Option %d: %s", code, text);
219                                 v_tree = gtk_tree_new();
220                                 add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
221                                 for (i = voff + 2; i < voff + consumed; i += 8) {
222                                         add_item_to_tree(v_tree, i, 4,
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
229                 /* DHCP Message Type */
230                 case 53:
231                         if (pd[voff+2] > 0 && pd[voff+2] < 9) {
232                                 i = pd[voff + 2];
233                         }
234                         else {
235                                 i = 0;
236                         }
237                         add_item_to_tree(bp_tree, voff, 3, "Option %d: %s = DHCP %s",
238                                 code, text, opt53_text[i]);
239                         return vlen + 2;
240
241                 /* Client Identifier */
242                 case 61:
243                         consumed = vlen + 2;
244                         /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
245                                 guess that the first is the hwtype, and the last 6 are
246                                 the hw addr */
247                         if (pd[voff+1] == 7) {
248                                 vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
249                                         consumed, "Option %d: %s", code, text);
250                                 v_tree = gtk_tree_new();
251                                 add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
252                                 add_item_to_tree(v_tree, voff+2, 1,
253                                         "Hardware type: 0x%02x", pd[voff+2]);
254                                 add_item_to_tree(v_tree, voff+3, 6,
255                                         "Client hardware address: %s",
256                                         ether_to_str((guint8*)&pd[voff+3]));
257                         }
258                         /* otherwise, it's opaque data */
259                         else {
260                                 add_item_to_tree(bp_tree, voff, consumed,
261                                         "Option %d: %s (%d bytes)", code, text, vlen);
262                         }
263                         return consumed;
264
265                 /* End Option */
266                 case 255:
267                         add_item_to_tree(bp_tree, voff, 1, "End Option", code);
268                         consumed = 1;
269                         return consumed;
270
271                 default:
272                         /* nothing */
273         }
274
275         /* Normal cases */
276         if (code < NUM_OPT_INFOS) {
277                 consumed = vlen + 2;
278                 text = opt[code].text;
279                 ftype = opt[code].ftype;
280
281                 switch (ftype) {
282                         case ipv4:
283                                 /* one IP address */
284                                 if (vlen == 4) {
285                                         add_item_to_tree(bp_tree, voff, consumed,
286                                                 "Option %d: %s = %s", code, text,
287                                                 ip_to_str((guint8*)&pd[voff+2]));
288                                 }
289                                 /* > 1 IP addresses. Let's make a sub-tree */
290                                 else {
291
292                                         vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
293                                                 consumed, "Option %d: %s", code, text);
294                                         v_tree = gtk_tree_new();
295                                         add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
296                                         for (i = voff + 2; i < voff + consumed; i += 4) {
297                                                 add_item_to_tree(v_tree, i, 4, "IP Address: %s",
298                                                         ip_to_str((guint8*)&pd[i]));
299                                         }
300                                 }
301                                 break;
302
303                         case string:
304                                 add_item_to_tree(bp_tree, voff, consumed,
305                                                 "Option %d: %s = %s", code, text, &pd[voff+2]);
306                                 break;
307
308                         case opaque:
309                                 add_item_to_tree(bp_tree, voff, consumed,
310                                                 "Option %d: %s (%d bytes)",
311                                                 code, text, vlen);
312                                 break;
313
314                         case val_u_short:
315                                 /* one IP address */
316                                 if (vlen == 2) {
317                                         add_item_to_tree(bp_tree, voff, consumed,
318                                                         "Option %d: %s = %d", code, text,
319                                                         pntohs(&pd[voff+2]));
320                                 }
321                                 /* > 1 u_short */
322                                 else {
323                                         vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
324                                                 consumed, "Option %d: %s", code, text);
325                                         v_tree = gtk_tree_new();
326                                         add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
327                                         for (i = voff + 2; i < voff + consumed; i += 2) {
328                                                 add_item_to_tree(v_tree, i, 4, "Value: %d",
329                                                         pntohs(&pd[i]));
330                                         }
331                                 }
332                                 break;
333
334                         case val_u_long:
335                                 add_item_to_tree(bp_tree, voff, consumed,
336                                                 "Option %d: %s = %d", code, text,
337                                                 pntohl(&pd[voff+2]));
338                                 break;
339
340                         case val_u_byte:
341                                 add_item_to_tree(bp_tree, voff, consumed,
342                                                 "Option %d: %s = %d", code, text, pd[voff+2]);
343                                 break;
344
345                         case toggle:
346                                 i = pd[voff+2];
347                                 if (i != 0 && i != 1) {
348                                         add_item_to_tree(bp_tree, voff, consumed,
349                                                         "Option %d: %s = Invalid Value %d", code, text,
350                                                         pd[voff+2]);
351                                 }
352                                 else {
353                                         add_item_to_tree(bp_tree, voff, consumed,
354                                                         "Option %d: %s = %s", code, text,
355                                                         pd[voff+2] == 0 ? "Disabled" : "Enabled");
356                                 }
357                                 break;
358
359                         case yes_no:
360                                 i = pd[voff+2];
361                                 if (i != 0 && i != 1) {
362                                         add_item_to_tree(bp_tree, voff, consumed,
363                                                         "Option %d: %s = Invalid Value %d", code, text,
364                                                         pd[voff+2]);
365                                 }
366                                 else {
367                                         add_item_to_tree(bp_tree, voff, consumed,
368                                                         "Option %d: %s = %s", code, text,
369                                                         pd[voff+2] == 0 ? "No" : "Yes");
370                                 }
371                                 break;
372
373                         default:
374                                 add_item_to_tree(bp_tree, voff, consumed, "Option %d: %s",
375                                         code, text);
376                 }
377         }
378         else {
379                 add_item_to_tree(bp_tree, voff, 1, "Unknown Option Code: %d", code);
380         }
381
382         return consumed;
383 }
384
385 void
386 dissect_bootp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
387 {
388         GtkWidget       *bp_tree, *ti;
389         int                     voff, eoff; /* vender offset, end offset */
390         int                     vlen;
391
392         if (fd->win_info[0]) {
393                 strcpy(fd->win_info[3], "BOOTP");
394
395                 /* if hwaddr is 6 bytes, assume MAC */
396                 if (pd[offset] == 1 && pd[offset+2] == 6) {
397                         sprintf(fd->win_info[4], "Boot Request from %s",
398                                 ether_to_str((guint8*)&pd[offset+28]));
399                 }
400                 else {
401                         strcpy(fd->win_info[4], pd[offset] == 1 ? "Boot Request" :
402                                 "Boot Reply");
403                 }
404         }
405
406         if (tree) {
407                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, fd->cap_len - offset,
408                   "Bootstrap Protocol");
409                 bp_tree = gtk_tree_new();
410                 add_subtree(ti, bp_tree, ETT_BOOTP);
411
412                 add_item_to_tree(bp_tree, offset, 1, pd[offset] == 1 ?
413                         "Boot Request" : "Boot Reply");
414                 add_item_to_tree(bp_tree, offset + 1, 1,
415                         "Hardware type: 0x%02x", pd[offset+1]);
416                 add_item_to_tree(bp_tree, offset + 2, 1,
417                         "Hardware address length: %d", pd[offset+2]);
418                 add_item_to_tree(bp_tree, offset + 3, 1,
419                         "Hops: %d", pd[offset+3]);
420                 add_item_to_tree(bp_tree, offset + 4, 4,
421                         "Transaction ID: 0x%08x", pntohl(&pd[offset+4]));
422                 add_item_to_tree(bp_tree, offset + 8, 2,
423                         "Seconds elapsed: %d", pntohs(&pd[offset+8]));
424                 add_item_to_tree(bp_tree, offset + 10, 2,
425                         "Broadcast flag: %d", pd[offset+10] & 1);
426                 add_item_to_tree(bp_tree, offset + 12, 4,
427                         "Client IP address: %s", ip_to_str((guint8*)&pd[offset+12]));
428                 add_item_to_tree(bp_tree, offset + 16, 4,
429                         "Your (client) IP address: %s", ip_to_str((guint8*)&pd[offset+16]));
430                 add_item_to_tree(bp_tree, offset + 20, 4,
431                         "Next server IP address: %s", ip_to_str((guint8*)&pd[offset+20]));
432                 add_item_to_tree(bp_tree, offset + 24, 4,
433                         "Relay agent IP address: %s", ip_to_str((guint8*)&pd[offset+24]));
434
435                 /* If HW address is 6 bytes, assume MAC. */
436                 if (pd[offset+2] == 6) {
437                         add_item_to_tree(bp_tree, offset + 28, 6,
438                                 "Client hardware address: %s",
439                                 ether_to_str((guint8*)&pd[offset+28]));
440                 }
441                 else {
442                         add_item_to_tree(bp_tree, offset + 28, 16,
443                                 "Client hardware address: %02x:%02x%02x:%02x:%02x:%02x:%02x:%02x%02x:%02x%02x:%02x:%02x:%02x:%02x:%02x",
444                                 pd[offset+28], pd[offset+29], pd[offset+30], pd[offset+31],
445                                 pd[offset+32], pd[offset+33], pd[offset+34], pd[offset+35],
446                                 pd[offset+36], pd[offset+37], pd[offset+38], pd[offset+39],
447                                 pd[offset+40], pd[offset+41], pd[offset+42], pd[offset+43]);
448                 }
449
450                 /* The server host name is optional */
451                 if (pd[offset+44]) {
452                         add_item_to_tree(bp_tree, offset + 44, 64,
453                                 "Server host name: %s", &pd[offset+44]);
454                 }
455                 else {
456                         add_item_to_tree(bp_tree, offset + 44, 64,
457                                 "Server host name not given");
458                 }
459
460                 /* Boot file */
461                 if (pd[offset+108]) {
462                         add_item_to_tree(bp_tree, offset + 108, 128,
463                                 "Boot file nme: %s", &pd[offset+108]);
464                 }
465                 else {
466                         add_item_to_tree(bp_tree, offset + 108, 128,
467                                 "Boot file name not given");
468                 }
469
470                 if (pntohl(&pd[offset+236]) ==  0x63538263) {
471                         add_item_to_tree(bp_tree, offset + 236, 4,
472                                 "Magic cookie: %s (generic)",
473                                         ip_to_str((guint8*)&pd[offset+236]));
474                 }
475                 else {
476                         add_item_to_tree(bp_tree, offset + 236, 4,
477                                 "Magic cookie: %s",
478                                         ip_to_str((guint8*)&pd[offset+236]));
479                 }
480
481                 voff = offset+240;
482                 eoff = fd->cap_len;
483
484                 while (voff < eoff) {
485                         voff += bootp_option(pd, bp_tree, voff, eoff);
486                 }
487         }
488 }
489