Check the checksum on GRE packets, if possible and if the Checksum
[obnox/wireshark/wip.git] / packet-portmap.c
1 /* packet-portmap.c
2  * Routines for portmap dissection
3  *
4  * $Id: packet-portmap.c,v 1.20 2000/08/24 23:16:16 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Copied from packet-smb.c
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35
36
37 #include "packet-rpc.h"
38 #include "packet-portmap.h"
39
40 /*
41  * See:
42  *
43  *      RFC 1833, "Binding Protocols for ONC RPC Version 2".
44  */
45
46 static int proto_portmap = -1;
47 static int hf_portmap_proto = -1;
48 static int hf_portmap_prog = -1;
49 static int hf_portmap_proc = -1;
50 static int hf_portmap_version = -1;
51 static int hf_portmap_port = -1;
52 static int hf_portmap_answer = -1;
53 static int hf_portmap_rpcb = -1;
54 static int hf_portmap_rpcb_prog = -1;
55 static int hf_portmap_rpcb_version = -1;
56 static int hf_portmap_rpcb_netid = -1;
57 static int hf_portmap_rpcb_addr = -1;
58 static int hf_portmap_rpcb_owner = -1;
59 static int hf_portmap_uaddr = -1;
60
61
62 static gint ett_portmap = -1;
63 static gint ett_portmap_rpcb = -1;
64 static gint ett_portmap_entry = -1;
65
66
67 /* Dissect a getport call */
68 int dissect_getport_call(const u_char *pd, int offset, frame_data *fd,
69         proto_tree *tree)
70 {
71         guint32 proto;
72         guint32 prog;
73         if ( !BYTES_ARE_IN_FRAME(offset, 16)) return offset;
74
75         if ( tree )
76         {
77                 prog = pntohl(&pd[offset+0]);
78                 proto_tree_add_uint_format(tree, hf_portmap_prog, NullTVB,
79                         offset, 4, prog, "Program: %s (%u)",
80                         rpc_prog_name(prog), prog);
81                 proto_tree_add_uint(tree, hf_portmap_version, NullTVB,
82                         offset+4, 4, pntohl(&pd[offset+4]));
83
84                 proto = pntohl(&pd[offset+8]);
85                 proto_tree_add_uint_format(tree, hf_portmap_proto, NullTVB,
86                         offset+8, 4, proto, "Proto: %s (%u)", ipprotostr(proto), proto);
87
88                 proto_tree_add_uint(tree, hf_portmap_port, NullTVB,
89                         offset+12, 4, pntohl(&pd[offset+12]));
90         }
91         
92         return offset+16;
93 }
94
95 int dissect_getport_reply(const u_char *pd, int offset, frame_data *fd,
96         proto_tree *tree)
97 {
98         if ( !BYTES_ARE_IN_FRAME(offset, 4)) return offset;
99         if ( tree )
100         {
101                 proto_tree_add_uint(tree, hf_portmap_port, NullTVB,
102                         offset, 4, pntohl(&pd[offset+0]));
103         }
104     return offset+=4;
105 }
106
107 /* Dissect a 'set' call */
108 int dissect_set_call(const u_char *pd, int offset, frame_data *fd,
109         proto_tree *tree)
110 {
111         guint32 proto;
112         guint32 prog;
113         if ( !BYTES_ARE_IN_FRAME(offset, 16)) return offset;
114
115         if ( tree )
116         {
117                 prog = pntohl(&pd[offset+0]);
118                 proto_tree_add_uint_format(tree, hf_portmap_prog, NullTVB,
119                         offset, 4, prog, "Program: %s (%d)",
120                         rpc_prog_name(prog), prog);
121                 proto_tree_add_uint(tree, hf_portmap_version, NullTVB,
122                         offset+4, 4, pntohl(&pd[offset+4]));
123
124                 proto = pntohl(&pd[offset+8]);
125                 proto_tree_add_uint_format(tree, hf_portmap_proto, NullTVB,
126                         offset+8, 4, proto, "Proto: %s (%d)", ipprotostr(proto), proto);
127
128                 proto_tree_add_uint(tree, hf_portmap_port, NullTVB,
129                         offset+12, 4, pntohl(&pd[offset+12]));
130         }
131         
132         return offset+16;
133 }
134
135 /* Dissect a 'unset' call */
136 int dissect_unset_call(const u_char *pd, int offset, frame_data *fd,
137         proto_tree *tree)
138 {
139         guint32 proto;
140         guint32 prog;
141         if ( !BYTES_ARE_IN_FRAME(offset, 16)) return offset;
142
143         if ( tree )
144         {
145                 prog = pntohl(&pd[offset+0]);
146                 proto_tree_add_uint_format(tree, hf_portmap_prog, NullTVB,
147                         offset, 4, prog, "Program: %s (%d)",
148                         rpc_prog_name(prog), prog);
149                 proto_tree_add_uint(tree, hf_portmap_version, NullTVB,
150                         offset+4, 4, pntohl(&pd[offset+4]));
151
152                 proto = pntohl(&pd[offset+8]);
153                 proto_tree_add_uint(tree, hf_portmap_proto, NullTVB,
154                         offset+8, 4, proto);
155
156                 proto_tree_add_uint(tree, hf_portmap_port, NullTVB,
157                         offset+12, 4, pntohl(&pd[offset+12]));
158         }
159         
160         return offset+16;
161 }
162
163 int dissect_set_reply(const u_char *pd, int offset, frame_data *fd,
164         proto_tree *tree)
165 {
166         if ( tree )
167         {
168                 if ( !BYTES_ARE_IN_FRAME(offset, 4)) return offset;
169
170                 proto_tree_add_boolean(tree, hf_portmap_answer, NullTVB,
171                         offset, 4, pntohl(&pd[offset+0]));
172                 offset += 4;
173         }
174     return offset;
175 }
176
177 static int
178 dissect_dump_entry(const u_char* pd, int offset, frame_data* fd, proto_tree* tree)
179 {
180         int prog, version, proto, port;
181         proto_item *ti, *subtree;
182
183         if ( ! BYTES_ARE_IN_FRAME(offset, 16) )
184         {
185                 if ( tree )
186                 {
187                         proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "Map Entry: <TRUNCATED>");
188                 }
189                 return pi.captured_len;
190         }
191         prog = pntohl(&pd[offset+0]);
192         version = pntohl(&pd[offset+4]);
193         proto = pntohl(&pd[offset+8]);
194         port = pntohl(&pd[offset+12]);
195         if ( tree )
196         {
197                 ti = proto_tree_add_text(tree, NullTVB, offset, 16, "Map Entry: %s (%u) V%d",
198                         rpc_prog_name(prog), prog, version);
199                 subtree = proto_item_add_subtree(ti, ett_portmap_entry);
200
201                 proto_tree_add_uint_format(subtree, hf_portmap_prog, NullTVB,
202                         offset+0, 4, prog,
203                         "Program: %s (%u)", rpc_prog_name(prog), prog);
204                 proto_tree_add_uint(subtree, hf_portmap_version, NullTVB,
205                         offset+4, 4, version);
206                 proto_tree_add_uint_format(subtree, hf_portmap_proto, NullTVB,
207                         offset+8, 4, proto, 
208                         "Protocol: %s (0x%02x)", ipprotostr(proto), proto);
209                 proto_tree_add_uint(subtree, hf_portmap_port, NullTVB,
210                         offset+12, 4, port);
211         }
212         offset += 16;
213         return offset;
214 }
215
216 int dissect_dump_reply(const u_char *pd, int offset, frame_data *fd,
217         proto_tree *tree)
218 {
219         offset = dissect_rpc_list(pd, offset, fd, tree, dissect_dump_entry);
220         return offset;
221 }
222
223 /* proc number, "proc name", dissect_request, dissect_reply */
224 /* NULL as function pointer means: take the generic one. */
225 const vsff portmap1_proc[] = {
226         { PORTMAPPROC_NULL,     "NULL",         NULL,                           NULL },
227         { PORTMAPPROC_SET,      "SET",          NULL,                           NULL },
228         { PORTMAPPROC_UNSET,    "UNSET",                NULL,                           NULL },
229         { PORTMAPPROC_GETPORT,  "GETPORT",              NULL,                           NULL },
230         { PORTMAPPROC_DUMP,     "DUMP",         NULL,                           NULL },
231         { PORTMAPPROC_CALLIT,   "CALLIT",               NULL,                           NULL },
232         { 0,    NULL,           NULL,                           NULL }
233 };
234 /* end of Portmap version 1 */
235
236 const vsff portmap2_proc[] = {
237         { PORTMAPPROC_NULL, "NULL",
238                 NULL, NULL },
239         { PORTMAPPROC_SET, "SET",
240                 dissect_set_call, dissect_set_reply },
241         { PORTMAPPROC_UNSET, "UNSET",
242                 dissect_unset_call, dissect_set_reply },
243         { PORTMAPPROC_GETPORT,  "GETPORT",
244                 dissect_getport_call, dissect_getport_reply },
245         { PORTMAPPROC_DUMP, "DUMP",
246                 NULL, dissect_dump_reply },
247         { PORTMAPPROC_CALLIT, "CALLIT",
248                 NULL, NULL },
249     { 0, NULL, NULL, NULL }
250 };
251 /* end of Portmap version 2 */
252
253
254 /* RFC 1833, Page 3 */
255 static int
256 dissect_rpcb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
257 {
258         proto_item* rpcb_item = NULL;
259         proto_tree* rpcb_tree = NULL;
260         int old_offset = offset;
261         guint32 prog;
262         guint32 version;
263
264         if (tree) {
265                 rpcb_item = proto_tree_add_item(tree, hf_portmap_rpcb, NullTVB,
266                         offset+0, END_OF_FRAME, FALSE);
267                 if (rpcb_item)
268                         rpcb_tree = proto_item_add_subtree(rpcb_item, ett_portmap_rpcb);
269         }
270
271         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
272         prog = EXTRACT_UINT(pd, offset + 0);
273         if (rpcb_tree)
274                 proto_tree_add_uint_format(rpcb_tree, hf_portmap_rpcb_prog, NullTVB,
275                         offset+0, 4, prog, 
276                         "Program: %s (%u)", rpc_prog_name(prog), prog);
277         offset += 4;
278
279         if (!BYTES_ARE_IN_FRAME(offset, 4)) return offset;
280         version = EXTRACT_UINT(pd, offset + 0);
281         if (rpcb_tree)
282                 proto_tree_add_uint(rpcb_tree, hf_portmap_rpcb_version, NullTVB,
283                         offset+0, 4, version);
284         offset += 4;
285
286         offset = dissect_rpc_string(pd, offset, fd, rpcb_tree, hf_portmap_rpcb_netid,NULL);
287         offset = dissect_rpc_string(pd, offset, fd, rpcb_tree, hf_portmap_rpcb_addr,NULL);
288         offset = dissect_rpc_string(pd, offset, fd, rpcb_tree, hf_portmap_rpcb_owner,NULL);
289
290         /* now we know, that rpcb is shorter */
291         if (rpcb_item) {
292                 proto_item_set_len(rpcb_item, offset - old_offset);
293         }
294
295         return offset;
296 }
297
298
299
300 /* RFC 1833, Page 7 */
301 int dissect_rpcb3_getaddr_call(const u_char *pd, int offset, frame_data *fd,
302         proto_tree *tree)
303 {
304         offset = dissect_rpcb(pd, offset, fd, tree);
305
306         return offset;
307 }
308
309
310 /* RFC 1833, Page 7 */
311 int dissect_rpcb3_getaddr_reply(const u_char *pd, int offset, frame_data *fd,
312         proto_tree *tree)
313 {
314         offset = dissect_rpc_string(pd, offset, fd, tree, hf_portmap_uaddr,NULL);
315
316         return offset;
317 }
318
319
320 /* RFC 1833, Page 7 */
321 int dissect_rpcb3_dump_reply(const u_char *pd, int offset, frame_data *fd,
322         proto_tree *tree)
323 {
324         offset = dissect_rpc_list(pd, offset, fd, tree, dissect_rpcb);
325         return offset;
326 }
327
328
329 /* Portmapper version 3, RFC 1833, Page 7 */
330 const vsff portmap3_proc[] = {
331         { RPCBPROC_NULL,        "NULL",
332                 NULL, NULL },
333         { RPCBPROC_SET,         "SET",
334                 NULL, NULL },
335         { RPCBPROC_UNSET,       "UNSET",
336                 NULL, NULL },
337         { RPCBPROC_GETADDR,     "GETADDR",
338                 dissect_rpcb3_getaddr_call, dissect_rpcb3_getaddr_reply},
339         { RPCBPROC_DUMP,        "DUMP",
340                 NULL, dissect_rpcb3_dump_reply },
341         { RPCBPROC_CALLIT,      "CALLIT",
342                 NULL, NULL },
343         { RPCBPROC_GETTIME,     "GETTIME",
344                 NULL, NULL },
345         { RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
346                 NULL, NULL },
347         { RPCBPROC_TADDR2UADDR, "TADDR2UADDR",
348                 NULL, NULL },
349         { 0, NULL, NULL, NULL }
350 };
351 /* end of Portmap version 3 */
352
353
354 /* Portmapper version 4, RFC 1833, Page 8 */
355 const vsff portmap4_proc[] = {
356         { RPCBPROC_NULL,        "NULL",
357                 NULL, NULL },
358         { RPCBPROC_SET,         "SET",
359                 NULL, NULL },
360         { RPCBPROC_UNSET,       "UNSET",
361                 NULL, NULL },
362         { RPCBPROC_GETADDR,     "GETADDR",
363                 dissect_rpcb3_getaddr_call, dissect_rpcb3_getaddr_reply},
364         { RPCBPROC_DUMP,        "DUMP",
365                 NULL, dissect_rpcb3_dump_reply },
366         { RPCBPROC_BCAST,       "BCAST",
367                 NULL, NULL },
368         { RPCBPROC_GETTIME,     "GETTIME",
369                 NULL, NULL },
370         { RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
371                 NULL, NULL },
372         { RPCBPROC_TADDR2UADDR, "TADDR2UADDR",
373                 NULL, NULL },
374         { RPCBPROC_GETVERSADDR, "GETVERSADDR",
375                 NULL, NULL },
376         { RPCBPROC_INDIRECT,    "INDIRECT",
377                 NULL, NULL },
378         { RPCBPROC_GETADDRLIST, "GETADDRLIST",
379                 NULL, NULL },
380         { RPCBPROC_GETSTAT,     "GETSTAT",
381                 NULL, NULL },
382         { 0, NULL, NULL, NULL }
383 };
384 /* end of Portmap version 4 */
385
386 void
387 proto_register_portmap(void)
388 {
389         static hf_register_info hf[] = {
390                 { &hf_portmap_prog, {
391                         "Program", "portmap.prog", FT_UINT32, BASE_DEC,
392                         NULL, 0, "Program" }},
393                 { &hf_portmap_port, {
394                         "Port", "portmap.port", FT_UINT32, BASE_DEC,
395                         NULL, 0, "Port" }},
396                 { &hf_portmap_proc, {
397                         "Procedure", "portmap.proc", FT_UINT32, BASE_DEC,
398                         NULL, 0, "Procedure" }},
399                 { &hf_portmap_proto, {
400                         "Protocol", "portmap.proto", FT_UINT32, BASE_DEC,
401                         NULL, 0, "Protocol" }},
402                 { &hf_portmap_version, {
403                         "Version", "portmap.version", FT_UINT32, BASE_DEC,
404                         NULL, 0, "Version" }},
405                 { &hf_portmap_answer, {
406                         "Answer", "portmap.answer", FT_BOOLEAN, BASE_DEC,
407                         NULL, 0, "Answer" }},
408                 { &hf_portmap_rpcb, {
409                         "RPCB", "portmap.rpcb", FT_NONE, 0,
410                         NULL, 0, "RPCB" }},
411                 { &hf_portmap_rpcb_prog, {
412                         "Program", "portmap.rpcb.prog", FT_UINT32, BASE_DEC,
413                         NULL, 0, "Program" }},
414                 { &hf_portmap_rpcb_version, {
415                         "Version", "portmap.rpcb.version", FT_UINT32, BASE_DEC,
416                         NULL, 0, "Version" }},
417                 { &hf_portmap_rpcb_netid, {
418                         "Network Id", "portmap.rpcb.netid", FT_STRING, BASE_DEC,
419                         NULL, 0, "Network Id" }},
420                 { &hf_portmap_rpcb_addr, {
421                         "Universal Address", "portmap.rpcb.addr", FT_STRING, BASE_DEC,
422                         NULL, 0, "Universal Address" }},
423                 { &hf_portmap_rpcb_owner, {
424                         "Owner of this Service", "portmap.rpcb.owner", FT_STRING, BASE_DEC,
425                         NULL, 0, "Owner of this Service" }},
426                 { &hf_portmap_uaddr, {
427                         "Universal Address", "portmap.uaddr", FT_STRING, BASE_DEC,
428                         NULL, 0, "Universal Address" }},
429         };
430         static gint *ett[] = {
431                 &ett_portmap,
432                 &ett_portmap_rpcb,
433                 &ett_portmap_entry
434         };
435
436         proto_portmap = proto_register_protocol("Portmap", "portmap");
437         proto_register_field_array(proto_portmap, hf, array_length(hf));
438         proto_register_subtree_array(ett, array_length(ett));
439 }
440
441 void
442 proto_reg_handoff_portmap(void)
443 {
444         /* Register the protocol as RPC */
445         rpc_init_prog(proto_portmap, PORTMAP_PROGRAM, ett_portmap);
446         /* Register the procedure tables */
447         rpc_init_proc_table(PORTMAP_PROGRAM, 1, portmap1_proc);
448         rpc_init_proc_table(PORTMAP_PROGRAM, 2, portmap2_proc);
449         rpc_init_proc_table(PORTMAP_PROGRAM, 3, portmap3_proc);
450         rpc_init_proc_table(PORTMAP_PROGRAM, 4, portmap4_proc);
451 }