f48311b21919d8248260b54e113a1fe0dd1c74eb
[obnox/wireshark/wip.git] / packet-portmap.c
1 /* packet-portmap.c
2  * Routines for portmap dissection
3  *
4  * $Id: packet-portmap.c,v 1.26 2001/02/06 06:56:19 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(tvbuff_t *tvb, int offset, packet_info *pinfo,
69         proto_tree *tree)
70 {
71         guint32 proto;
72         guint32 prog;
73
74         if ( tree )
75         {
76                 prog = tvb_get_ntohl(tvb, offset+0);
77                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
78                         offset, 4, prog, "Program: %s (%u)",
79                         rpc_prog_name(prog), prog);
80                 proto_tree_add_item(tree, hf_portmap_version, tvb,
81                         offset+4, 4, FALSE);
82
83                 proto = tvb_get_ntohl(tvb, offset+8);
84                 proto_tree_add_uint_format(tree, hf_portmap_proto, tvb,
85                         offset+8, 4, proto, "Proto: %s (%u)", ipprotostr(proto), proto);
86
87                 proto_tree_add_item(tree, hf_portmap_port, tvb,
88                         offset+12, 4, FALSE);
89         }
90         
91         return offset+16;
92 }
93
94 int dissect_getport_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
95         proto_tree *tree)
96 {
97         offset = dissect_rpc_uint32_tvb(tvb, pinfo, tree, hf_portmap_port,
98             offset);
99         return offset;
100 }
101
102 /* Dissect a 'set' call */
103 int dissect_set_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
104         proto_tree *tree)
105 {
106         guint32 proto;
107         guint32 prog;
108
109         if ( tree )
110         {
111                 prog = tvb_get_ntohl(tvb, offset+0);
112                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
113                         offset, 4, prog, "Program: %s (%d)",
114                         rpc_prog_name(prog), prog);
115                 proto_tree_add_item(tree, hf_portmap_version, tvb,
116                         offset+4, 4, FALSE);
117
118                 proto = tvb_get_ntohl(tvb, offset+8);
119                 proto_tree_add_uint_format(tree, hf_portmap_proto,tvb,
120                         offset+8, 4, proto, "Proto: %s (%d)", ipprotostr(proto), proto);
121
122                 proto_tree_add_item(tree, hf_portmap_port, tvb,
123                         offset+12, 4, FALSE);
124         }
125         
126         return offset+16;
127 }
128
129 /* Dissect a 'unset' call */
130 int dissect_unset_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
131         proto_tree *tree)
132 {
133         guint32 proto;
134         guint32 prog;
135
136         if ( tree )
137         {
138                 prog = tvb_get_ntohl(tvb, offset+0);
139                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
140                         offset, 4, prog, "Program: %s (%d)",
141                         rpc_prog_name(prog), prog);
142                 proto_tree_add_item(tree, hf_portmap_version, tvb,
143                         offset+4, 4, FALSE);
144
145                 proto = tvb_get_ntohl(tvb, offset+8);
146                 proto_tree_add_uint(tree, hf_portmap_proto, tvb,
147                         offset+8, 4, proto);
148
149                 proto_tree_add_item(tree, hf_portmap_port, tvb,
150                         offset+12, 4, FALSE);
151         }
152
153         return offset+16;
154 }
155
156 int dissect_set_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
157         proto_tree *tree)
158 {
159         offset = dissect_rpc_bool_tvb(tvb, pinfo, tree, hf_portmap_answer,
160             offset);
161         return offset;
162 }
163
164 static int
165 dissect_dump_entry(tvbuff_t *tvb, int offset, packet_info *pinfo,
166         proto_tree *tree)
167 {
168         int prog, version, proto, port;
169         proto_item *ti, *subtree;
170
171         prog = tvb_get_ntohl(tvb, offset+0);
172         version = tvb_get_ntohl(tvb, offset+4);
173         proto = tvb_get_ntohl(tvb, offset+8);
174         port = tvb_get_ntohl(tvb, offset+12);
175         if ( tree )
176         {
177                 ti = proto_tree_add_text(tree, tvb, offset, 16,
178                         "Map Entry: %s (%u) V%d",
179                         rpc_prog_name(prog), prog, version);
180                 subtree = proto_item_add_subtree(ti, ett_portmap_entry);
181
182                 proto_tree_add_uint_format(subtree, hf_portmap_prog, tvb,
183                         offset+0, 4, prog,
184                         "Program: %s (%u)", rpc_prog_name(prog), prog);
185                 proto_tree_add_uint(subtree, hf_portmap_version, tvb,
186                         offset+4, 4, version);
187                 proto_tree_add_uint_format(subtree, hf_portmap_proto, tvb,
188                         offset+8, 4, proto, 
189                         "Protocol: %s (0x%02x)", ipprotostr(proto), proto);
190                 proto_tree_add_uint(subtree, hf_portmap_port, tvb,
191                         offset+12, 4, port);
192         }
193         offset += 16;
194         return offset;
195 }
196
197 int dissect_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
198         proto_tree *tree)
199 {
200         offset = dissect_rpc_list_tvb(tvb, pinfo, tree, offset,
201                 dissect_dump_entry);
202         return offset;
203 }
204
205 /* Dissect a callit call */
206 int dissect_callit_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
207         proto_tree *tree)
208 {
209         rpc_proc_info_key key;
210         rpc_proc_info_value *value;
211         char *procname = NULL;
212         char procname_static[20];
213         old_dissect_function_t *old_dissect_function = NULL;
214         dissect_function_t *dissect_function = NULL;
215
216         key.prog = tvb_get_ntohl(tvb, offset+0);
217         if ( tree )
218         {
219                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
220                         offset, 4, key.prog, "Program: %s (%u)",
221                         rpc_prog_name(key.prog), key.prog);
222         }
223
224         key.vers = tvb_get_ntohl(tvb, offset+4);
225         if ( tree )
226         {
227                 proto_tree_add_uint(tree, hf_portmap_version, tvb,
228                         offset+4, 4, key.vers);
229         }
230
231         key.proc = tvb_get_ntohl(tvb, offset+8);
232         if ((value = g_hash_table_lookup(rpc_procs,&key)) != NULL) {
233                 if (value->is_old_dissector)
234                         old_dissect_function = value->dissect_call.old;
235                 else
236                         dissect_function = value->dissect_call.new;
237                 procname = value->name;
238         }
239         else {
240                 /* happens only with strange program versions or
241                    non-existing dissectors */
242 #if 0
243                 dissect_function = NULL;
244 #endif
245                 sprintf(procname_static, "proc-%u", key.proc);
246                 procname = procname_static;
247         }
248         if ( tree )
249         {
250                 proto_tree_add_uint_format(tree, hf_portmap_proc, tvb,
251                         offset+8, 4, key.proc, "Procedure: %s (%u)",
252                         procname, key.proc);
253         }
254
255         if ( tree )
256         {
257                 proto_tree_add_text(tree, tvb, offset+12, 4,
258                         "Argument length: %u",
259                         tvb_get_ntohl(tvb, offset+12));
260         }
261
262         offset += 16;
263
264         /* Call the call dissector to dissect the opaque arguments.
265            Make the columns non-writable, so it won't change them out
266            from under us. */
267         col_set_writable(pinfo->fd, FALSE);
268         offset = call_dissect_function(tvb, pinfo, tree, offset,
269                         old_dissect_function, dissect_function, NULL);
270
271         return offset;
272 }
273
274 /*
275  * XXX - to dissect a CALLIT reply, we'd need to somehow associate
276  * the program/version/procedure information we get on a call with
277  * the RPC dissector's information about the call, and get that
278  * information from the reply dissector.
279  */
280
281 /* proc number, "proc name", dissect_request, dissect_reply */
282 /* NULL as function pointer means: type of arguments is "void". */
283 static const vsff portmap1_proc[] = {
284         { PORTMAPPROC_NULL,     "NULL",         NULL,   NULL },
285         { PORTMAPPROC_SET,      "SET",          NULL,   NULL },
286         { PORTMAPPROC_UNSET,    "UNSET",        NULL,   NULL },
287         { PORTMAPPROC_GETPORT,  "GETPORT",      NULL,   NULL },
288         { PORTMAPPROC_DUMP,     "DUMP",         NULL,   NULL },
289         { PORTMAPPROC_CALLIT,   "CALLIT",       NULL,   NULL },
290         { 0,                    NULL,           NULL,   NULL }
291 };
292 /* end of Portmap version 1 */
293
294 static const vsff portmap2_proc[] = {
295         { PORTMAPPROC_NULL, "NULL",
296                 NULL, NULL },
297         { PORTMAPPROC_SET, "SET",
298                 dissect_set_call, dissect_set_reply },
299         { PORTMAPPROC_UNSET, "UNSET",
300                 dissect_unset_call, dissect_set_reply },
301         { PORTMAPPROC_GETPORT,  "GETPORT",
302                 dissect_getport_call, dissect_getport_reply },
303         { PORTMAPPROC_DUMP, "DUMP",
304                 NULL, dissect_dump_reply },
305         { PORTMAPPROC_CALLIT, "CALLIT",
306                 dissect_callit_call, NULL },
307         { 0, NULL, NULL, NULL }
308 };
309 /* end of Portmap version 2 */
310
311
312 /* RFC 1833, Page 3 */
313 static int
314 dissect_rpcb(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
315 {
316         proto_item* rpcb_item = NULL;
317         proto_tree* rpcb_tree = NULL;
318         int old_offset = offset;
319         guint32 prog;
320
321         if (tree) {
322                 rpcb_item = proto_tree_add_item(tree, hf_portmap_rpcb, tvb,
323                         offset, tvb_length(tvb), FALSE);
324                 if (rpcb_item)
325                         rpcb_tree = proto_item_add_subtree(rpcb_item, ett_portmap_rpcb);
326         }
327
328         prog = tvb_get_ntohl(tvb, offset);
329         if (rpcb_tree)
330                 proto_tree_add_uint_format(rpcb_tree, hf_portmap_rpcb_prog, tvb,
331                         offset, 4, prog, 
332                         "Program: %s (%u)", rpc_prog_name(prog), prog);
333         offset += 4;
334
335         offset = dissect_rpc_uint32_tvb(tvb, pinfo, rpcb_tree,
336             hf_portmap_rpcb_version, offset);
337         offset = dissect_rpc_string_tvb(tvb, pinfo, rpcb_tree,
338             hf_portmap_rpcb_netid, offset, NULL);
339         offset = dissect_rpc_string_tvb(tvb, pinfo, rpcb_tree,
340             hf_portmap_rpcb_addr, offset, NULL);
341         offset = dissect_rpc_string_tvb(tvb, pinfo, rpcb_tree,
342             hf_portmap_rpcb_owner, offset, NULL);
343
344         /* now we know, that rpcb is shorter */
345         if (rpcb_item) {
346                 proto_item_set_len(rpcb_item, offset - old_offset);
347         }
348
349         return offset;
350 }
351
352
353
354 /* RFC 1833, Page 7 */
355 int dissect_rpcb3_getaddr_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
356         proto_tree *tree)
357 {
358         offset = dissect_rpcb(tvb, offset, pinfo, tree);
359
360         return offset;
361 }
362
363
364 /* RFC 1833, Page 7 */
365 int dissect_rpcb3_getaddr_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
366         proto_tree *tree)
367 {
368         offset = dissect_rpc_string_tvb(tvb, pinfo, tree,
369             hf_portmap_uaddr, offset, NULL);
370
371         return offset;
372 }
373
374
375 /* RFC 1833, Page 7 */
376 int dissect_rpcb3_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
377         proto_tree *tree)
378 {
379         offset = dissect_rpc_list_tvb(tvb, pinfo, tree, offset, dissect_rpcb);
380         return offset;
381 }
382
383
384 /* Portmapper version 3, RFC 1833, Page 7 */
385 static const vsff portmap3_proc[] = {
386         { RPCBPROC_NULL,        "NULL",
387                 NULL, NULL },
388         { RPCBPROC_SET,         "SET",
389                 NULL, NULL },
390         { RPCBPROC_UNSET,       "UNSET",
391                 NULL, NULL },
392         { RPCBPROC_GETADDR,     "GETADDR",
393                 dissect_rpcb3_getaddr_call, dissect_rpcb3_getaddr_reply},
394         { RPCBPROC_DUMP,        "DUMP",
395                 NULL, dissect_rpcb3_dump_reply },
396         { RPCBPROC_CALLIT,      "CALLIT",
397                 dissect_callit_call, NULL },
398         { RPCBPROC_GETTIME,     "GETTIME",
399                 NULL, NULL },
400         { RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
401                 NULL, NULL },
402         { RPCBPROC_TADDR2UADDR, "TADDR2UADDR",
403                 NULL, NULL },
404         { 0, NULL, NULL, NULL }
405 };
406 /* end of Portmap version 3 */
407
408
409 /* Portmapper version 4, RFC 1833, Page 8 */
410 static const vsff portmap4_proc[] = {
411         { RPCBPROC_NULL,        "NULL",
412                 NULL, NULL },
413         { RPCBPROC_SET,         "SET",
414                 NULL, NULL },
415         { RPCBPROC_UNSET,       "UNSET",
416                 NULL, NULL },
417         { RPCBPROC_GETADDR,     "GETADDR",
418                 dissect_rpcb3_getaddr_call, dissect_rpcb3_getaddr_reply},
419         { RPCBPROC_DUMP,        "DUMP",
420                 NULL, dissect_rpcb3_dump_reply },
421         { RPCBPROC_BCAST,       "BCAST",
422                 dissect_callit_call, NULL },
423         { RPCBPROC_GETTIME,     "GETTIME",
424                 NULL, NULL },
425         { RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
426                 NULL, NULL },
427         { RPCBPROC_TADDR2UADDR, "TADDR2UADDR",
428                 NULL, NULL },
429         { RPCBPROC_GETVERSADDR, "GETVERSADDR",
430                 NULL, NULL },
431         { RPCBPROC_INDIRECT,    "INDIRECT",
432                 dissect_callit_call, NULL },
433         { RPCBPROC_GETADDRLIST, "GETADDRLIST",
434                 NULL, NULL },
435         { RPCBPROC_GETSTAT,     "GETSTAT",
436                 NULL, NULL },
437         { 0, NULL, NULL, NULL }
438 };
439 /* end of Portmap version 4 */
440
441 void
442 proto_register_portmap(void)
443 {
444         static hf_register_info hf[] = {
445                 { &hf_portmap_prog, {
446                         "Program", "portmap.prog", FT_UINT32, BASE_DEC,
447                         NULL, 0, "Program" }},
448                 { &hf_portmap_port, {
449                         "Port", "portmap.port", FT_UINT32, BASE_DEC,
450                         NULL, 0, "Port" }},
451                 { &hf_portmap_proc, {
452                         "Procedure", "portmap.proc", FT_UINT32, BASE_DEC,
453                         NULL, 0, "Procedure" }},
454                 { &hf_portmap_proto, {
455                         "Protocol", "portmap.proto", FT_UINT32, BASE_DEC,
456                         NULL, 0, "Protocol" }},
457                 { &hf_portmap_version, {
458                         "Version", "portmap.version", FT_UINT32, BASE_DEC,
459                         NULL, 0, "Version" }},
460                 { &hf_portmap_answer, {
461                         "Answer", "portmap.answer", FT_BOOLEAN, BASE_DEC,
462                         NULL, 0, "Answer" }},
463                 { &hf_portmap_rpcb, {
464                         "RPCB", "portmap.rpcb", FT_NONE, 0,
465                         NULL, 0, "RPCB" }},
466                 { &hf_portmap_rpcb_prog, {
467                         "Program", "portmap.rpcb.prog", FT_UINT32, BASE_DEC,
468                         NULL, 0, "Program" }},
469                 { &hf_portmap_rpcb_version, {
470                         "Version", "portmap.rpcb.version", FT_UINT32, BASE_DEC,
471                         NULL, 0, "Version" }},
472                 { &hf_portmap_rpcb_netid, {
473                         "Network Id", "portmap.rpcb.netid", FT_STRING, BASE_DEC,
474                         NULL, 0, "Network Id" }},
475                 { &hf_portmap_rpcb_addr, {      /* address in rpcb structure in request */
476                         "Universal Address", "portmap.rpcb.addr", FT_STRING, BASE_DEC,
477                         NULL, 0, "Universal Address" }},
478                 { &hf_portmap_rpcb_owner, {
479                         "Owner of this Service", "portmap.rpcb.owner", FT_STRING, BASE_DEC,
480                         NULL, 0, "Owner of this Service" }},
481                 { &hf_portmap_uaddr, {  /* address in RPCBPROC_GETADDR reply */
482                         "Universal Address", "portmap.uaddr", FT_STRING, BASE_DEC,
483                         NULL, 0, "Universal Address" }},
484         };
485         static gint *ett[] = {
486                 &ett_portmap,
487                 &ett_portmap_rpcb,
488                 &ett_portmap_entry
489         };
490
491         proto_portmap = proto_register_protocol("Portmap", "Portmap", "portmap");
492         proto_register_field_array(proto_portmap, hf, array_length(hf));
493         proto_register_subtree_array(ett, array_length(ett));
494 }
495
496 void
497 proto_reg_handoff_portmap(void)
498 {
499         /* Register the protocol as RPC */
500         rpc_init_prog(proto_portmap, PORTMAP_PROGRAM, ett_portmap);
501         /* Register the procedure tables */
502         rpc_init_proc_table(PORTMAP_PROGRAM, 1, portmap1_proc);
503         rpc_init_proc_table(PORTMAP_PROGRAM, 2, portmap2_proc);
504         rpc_init_proc_table(PORTMAP_PROGRAM, 3, portmap3_proc);
505         rpc_init_proc_table(PORTMAP_PROGRAM, 4, portmap4_proc);
506 }