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