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