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