checkAPIs.pl: support for new-style dissectors in check_hf_entries
[metze/wireshark/wip.git] / epan / dissectors / packet-ajp13.c
1 /* packet-ajp13.c
2  * Routines for AJP13 dissection
3  * Copyright 2002, Christopher K. St. John <cks@distributopia.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 #include "config.h"
13
14 #include <stdlib.h>
15
16 #include <epan/packet.h>
17 #include <epan/proto_data.h>
18 #include <epan/expert.h>
19 #include "packet-tcp.h"
20
21 #include <wsutil/strtoi.h>
22
23 void proto_register_ajp13(void);
24 void proto_reg_handoff_ajp13(void);
25
26 #define AJP13_TCP_PORT 8009 /* Not IANA registered */
27
28 /* IMPORTANT IMPLEMENTATION NOTES
29  *
30  * You need to be looking at:
31  *
32  *     http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
33  *
34  * If you're a wireshark dissector guru, then you can skip the rest of
35  * this. I'm writing it all down because I've written 3 dissectors so
36  * far and every time I've forgotten it all and had to re-learn it
37  * from scratch. Not this time, damnit.
38  *
39  * Dissector routines get called in two phases:
40  *
41  * The first phase is an in-order traversal of every incoming
42  * frame. Since we know it's in-order, we can set up a "conversational
43  * state" that records context-sensitive stuff like "was there a
44  * content-length in the previous request". During this first pass
45  * through the data, the "tree" parameter might be null, or not. For
46  * the regular gui-based Wireshark, it's null, which means we don't
47  * actually display the dissected data in the gui quite yet. For the
48  * text based interface, we might do the parsing and display both in
49  * this first pass.
50  *
51  * The second phase happens when the data is actually displayed. In
52  * this pase the "tree" param is non-null, so you've got a hook to
53  * hang the parsed-out display data on. Since there might be gigabytes
54  * worth of capture data, the display code only calls the dissector
55  * for the stuff the user actually clicks on. So you have to assume
56  * the dissector is getting called on random frames, you can't depend
57  * on ordering anymore.
58  *
59  * But some parts of the AJP13 capture stream are context sensitive.
60  * That's no big deal during the first in-order pass, but the second
61  * phase requires us to display any random frame correctly. So during
62  * the first in-order phase we create a per-frame user data structure
63  * and attach it to the frame using p_add_proto_data.
64  *
65  * Since AJP13 is a TCP/IP based protocol, writing a dissector for it
66  * requires addressing several other issues:
67  *
68  * 1) TCP/IP segments can get retransmitted or be sent out of
69  * order. Users don't normally care, because the low-level kernel
70  * networking code takes care of reassembling them properly. But we're
71  * looking at raw network packets, aren't we? The stuff on the
72  * wire. Wireshark has been getting better and better at helping
73  * dissectors with this. I'm a little fuzzy on the details, but my
74  * understanding is that wireshark now contains a fairly substantial
75  * user-space TCP/IP stack so it can re-assemble the data. But I might
76  * be wrong. Since AJP13 is going to be used either on the loopback
77  * interface or on a LAN, it isn't likely to be a big issues anyway.
78  *
79  * 2) AJP13 packets (PDU's or protocol data unit's in
80  * networking-speak) don't necessarily line up with TCP segments. That
81  * is, one TCP segment can have more than one AJP13 PDU, or one AJP13
82  * PDU can stretch across multiple TCP segments. Assembling them is
83  * obviously possible, but a royal pain. During the "phase one"
84  * in-order pass you have to keep track of a bunch of offsets and
85  * store which PDU goes with which TCP segment. Luckily, recent
86  * (0.9.4+) versions of wireshark provide the "tcp_dissect_pdus()"
87  * function that takes care of much of the work. See the comments in
88  * packet-tcp.c, the example code in packet-dns.c, or check the
89  * wireshark-dev archives for details.
90  *
91  * 3) Wireshark isn't guaranteed to see all the data. I'm a little
92  * unclear on all the possible failure modes, but it comes down to: a)
93  * Not your fault: it's an imperfect world, we're eavesdroppers, and
94  * stuff happens. We might totally miss packets or get garbled
95  * data. Or b) Totally your fault: you turn on the capture during the
96  * middle of an AJP13 conversation and the capture starts out with
97  * half an AJP13 PDU. This code doesn't currently handle either case
98  * very well, but you can get arbitrarily clever. Like: put in tests
99  * to see if this packet has reasonable field values, and if it
100  * doesn't, walk the offset ahead until we see a matching magic number
101  * field, then re-test. But we don't do that now, and since we're
102  * using tcp_dissect_pdu's, I'm not sure how to do it.
103  *
104  */
105
106
107
108 #define MTYPE_FORWARD_REQUEST   2
109 #define MTYPE_SEND_BODY_CHUNK   3
110 #define MTYPE_SEND_HEADERS      4
111 #define MTYPE_END_RESPONSE      5
112 #define MTYPE_GET_BODY_CHUNK    6
113 #define MTYPE_SHUTDOWN          7
114 #define MTYPE_CPONG             9
115 #define MTYPE_CPING             10
116
117 static const value_string mtype_codes[] = {
118   { MTYPE_FORWARD_REQUEST, "FORWARD REQUEST" },
119   { MTYPE_SEND_BODY_CHUNK, "SEND BODY CHUNK" },
120   { MTYPE_SEND_HEADERS,    "SEND HEADERS" },
121   { MTYPE_END_RESPONSE,    "END RESPONSE" },
122   { MTYPE_GET_BODY_CHUNK,  "GET BODY CHUNK" },
123   { MTYPE_SHUTDOWN,        "SHUTDOWN" },
124   { MTYPE_CPONG,           "CPONG" },
125   { MTYPE_CPING,           "CPING" },
126   { 0, NULL }
127 };
128
129
130 static const value_string http_method_codes[] = {
131   { 1, "OPTIONS" },
132   { 2, "GET" },
133   { 3, "HEAD" },
134   { 4, "POST" },
135   { 5, "PUT" },
136   { 6, "DELETE" },
137   { 7, "TRACE" },
138   { 8, "PROPFIND" },
139   { 9, "PROPPATCH" },
140   { 10, "MKCOL" },
141   { 11, "COPY" },
142   { 12, "MOVE" },
143   { 13, "LOCK" },
144   { 14, "UNLOCK" },
145   { 15, "ACL" },
146   { 16, "REPORT" },
147   { 17, "VERSION-CONTROL" },
148   { 18, "CHECKIN" },
149   { 19, "CHECKOUT" },
150   { 20, "UNCHECKOUT" },
151   { 21, "SEARCH" },
152   { 0, NULL }
153 };
154
155
156
157 static int proto_ajp13     = -1;
158 static int hf_ajp13_magic  = -1;
159 static int hf_ajp13_len    = -1;
160 static int hf_ajp13_code   = -1;
161 static int hf_ajp13_method = -1;
162 static int hf_ajp13_ver    = -1;
163 static int hf_ajp13_uri    = -1;
164 static int hf_ajp13_raddr  = -1;
165 static int hf_ajp13_rhost  = -1;
166 static int hf_ajp13_srv    = -1;
167 static int hf_ajp13_port   = -1;
168 static int hf_ajp13_sslp   = -1;
169 static int hf_ajp13_nhdr   = -1;
170
171 /* response headers */
172 static int hf_ajp13_unknown_header    = -1;
173 static int hf_ajp13_additional_header = -1;
174 static int hf_ajp13_content_type      = -1;
175 static int hf_ajp13_content_language  = -1;
176 static int hf_ajp13_content_length    = -1;
177 static int hf_ajp13_date              = -1;
178 static int hf_ajp13_last_modified     = -1;
179 static int hf_ajp13_location          = -1;
180 static int hf_ajp13_set_cookie        = -1;
181 static int hf_ajp13_set_cookie2       = -1;
182 static int hf_ajp13_servlet_engine    = -1;
183 static int hf_ajp13_status            = -1;
184 static int hf_ajp13_www_authenticate  = -1;
185
186 /* request headers */
187 static int hf_ajp13_accept            = -1;
188 static int hf_ajp13_accept_charset    = -1;
189 static int hf_ajp13_accept_encoding   = -1;
190 static int hf_ajp13_accept_language   = -1;
191 static int hf_ajp13_authorization     = -1;
192 static int hf_ajp13_connection        = -1;
193                  /* content_type   */
194                  /* content_length */
195 static int hf_ajp13_cookie            = -1;
196 static int hf_ajp13_cookie2           = -1;
197 static int hf_ajp13_host              = -1;
198 static int hf_ajp13_pragma            = -1;
199 static int hf_ajp13_referer           = -1;
200 static int hf_ajp13_user_agent        = -1;
201
202 /* request attributes */
203 static int hf_ajp13_unknown_attribute     = -1;
204 static int hf_ajp13_req_attribute         = -1;
205 static int hf_ajp13_context               = -1;
206 static int hf_ajp13_servlet_path          = -1;
207 static int hf_ajp13_remote_user           = -1;
208 static int hf_ajp13_auth_type             = -1;
209 static int hf_ajp13_query_string          = -1;
210 static int hf_ajp13_route                 = -1;
211 static int hf_ajp13_ssl_cert              = -1;
212 static int hf_ajp13_ssl_cipher            = -1;
213 static int hf_ajp13_ssl_session           = -1;
214 static int hf_ajp13_ssl_key_size          = -1;
215 static int hf_ajp13_secret                = -1;
216 static int hf_ajp13_stored_method         = -1;
217
218 static int hf_ajp13_rlen   = -1;
219 static int hf_ajp13_reusep = -1;
220 static int hf_ajp13_rstatus= -1;
221 static int hf_ajp13_rsmsg  = -1;
222 static int hf_ajp13_data   = -1;
223 static gint ett_ajp13 = -1;
224
225 static expert_field ei_ajp13_content_length_invalid = EI_INIT;
226
227 /*
228  * Request/response header codes. Common headers are stored as ints in
229  * an effort to improve performance. Why can't we just have one big
230  * list?
231  */
232 static const int* rsp_headers[] = {
233   &hf_ajp13_unknown_header,
234   &hf_ajp13_content_type,
235   &hf_ajp13_content_language,
236   &hf_ajp13_content_length,
237   &hf_ajp13_date,
238   &hf_ajp13_last_modified,
239   &hf_ajp13_location,
240   &hf_ajp13_set_cookie,
241   &hf_ajp13_set_cookie2,
242   &hf_ajp13_servlet_engine,
243   &hf_ajp13_status,
244   &hf_ajp13_www_authenticate
245 };
246
247 static const int* req_headers[] = {
248   &hf_ajp13_unknown_header,
249   &hf_ajp13_accept,
250   &hf_ajp13_accept_charset,
251   &hf_ajp13_accept_encoding,
252   &hf_ajp13_accept_language,
253   &hf_ajp13_authorization,
254   &hf_ajp13_connection,
255   &hf_ajp13_content_type,
256   &hf_ajp13_content_length,
257   &hf_ajp13_cookie,
258   &hf_ajp13_cookie2,
259   &hf_ajp13_host,
260   &hf_ajp13_pragma,
261   &hf_ajp13_referer,
262   &hf_ajp13_user_agent
263 };
264
265 static const int* req_attributes[] = {
266   &hf_ajp13_unknown_attribute,
267   &hf_ajp13_context,
268   &hf_ajp13_servlet_path,
269   &hf_ajp13_remote_user,
270   &hf_ajp13_auth_type,
271   &hf_ajp13_query_string,
272   &hf_ajp13_route,
273   &hf_ajp13_ssl_cert,
274   &hf_ajp13_ssl_cipher,
275   &hf_ajp13_ssl_session,
276   &hf_ajp13_req_attribute, /* 0x0A - name and value follows */
277   &hf_ajp13_ssl_key_size,
278   &hf_ajp13_secret,
279   &hf_ajp13_stored_method
280 };
281
282 typedef struct ajp13_conv_data {
283   int content_length;
284   gboolean was_get_body_chunk;  /* XXX - not used */
285 } ajp13_conv_data;
286
287 typedef struct ajp13_frame_data {
288   gboolean is_request_body;
289 } ajp13_frame_data;
290
291 /* ajp13, in sort of a belt-and-suspenders move, encodes strings with
292  * both a leading length field, and a trailing null. Mostly, see
293  * ajpv13a.html. The returned length _includes_ the trailing null, if
294  * there is one.
295  *
296  * XXX - is there a tvbuff routine to handle this?
297  */
298 static const gchar *
299 ajp13_get_nstring(tvbuff_t *tvb, gint offset, guint16* ret_len)
300 {
301   guint16 len;
302
303   len = tvb_get_ntohs(tvb, offset);
304
305   if (ret_len)
306     *ret_len = len+1;
307
308   /* a size of 0xFFFF indicates a null string - no data follows */
309   if (len == 0xFFFF)
310     len = 0;
311
312   return tvb_format_text(tvb, offset+2, MIN(len, ITEM_LABEL_LENGTH));
313 }
314
315
316
317 /* dissect a response. more work to do here.
318  */
319 static void
320 display_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ajp13_tree, ajp13_conv_data* cd)
321 {
322   int pos = 0;
323   guint8 mcode = 0;
324   int i;
325
326   /* MAGIC
327    */
328   if (ajp13_tree)
329     proto_tree_add_item(ajp13_tree, hf_ajp13_magic, tvb, pos, 2, ENC_NA);
330   pos+=2;
331
332   /* PDU LENGTH
333    */
334   if (ajp13_tree)
335     proto_tree_add_item(ajp13_tree, hf_ajp13_len,   tvb, pos, 2, ENC_BIG_ENDIAN);
336   pos+=2;
337
338   /* MESSAGE TYPE CODE
339    */
340   mcode = tvb_get_guint8(tvb, pos);
341   col_append_str(pinfo->cinfo, COL_INFO, val_to_str(mcode, mtype_codes, "Unknown message code %u"));
342   if (ajp13_tree)
343     proto_tree_add_item(ajp13_tree, hf_ajp13_code, tvb, pos, 1, ENC_BIG_ENDIAN);
344   pos+=1;
345
346   switch (mcode) {
347
348   case MTYPE_END_RESPONSE:
349     if (ajp13_tree)
350       proto_tree_add_item(ajp13_tree, hf_ajp13_reusep, tvb, pos, 1, ENC_BIG_ENDIAN);
351     /*pos+=1;*/
352     break;
353
354   case MTYPE_SEND_HEADERS:
355   {
356     const gchar *rsmsg;
357     guint16 rsmsg_len;
358     guint16 nhdr;
359     guint16 rcode_num;
360
361     /* HTTP RESPONSE STATUS CODE
362      */
363     rcode_num = tvb_get_ntohs(tvb, pos);
364     col_append_fstr(pinfo->cinfo, COL_INFO, ":%d", rcode_num);
365     if (ajp13_tree)
366       proto_tree_add_item(ajp13_tree, hf_ajp13_rstatus, tvb, pos, 2, ENC_BIG_ENDIAN);
367     pos+=2;
368
369     /* HTTP RESPONSE STATUS MESSAGE
370      */
371     rsmsg = ajp13_get_nstring(tvb, pos, &rsmsg_len);
372     col_append_fstr(pinfo->cinfo, COL_INFO, " %s", rsmsg);
373     if (ajp13_tree)
374       proto_tree_add_string(ajp13_tree, hf_ajp13_rsmsg, tvb, pos, rsmsg_len+2, rsmsg);
375     pos+=rsmsg_len+2;
376
377     /* NUMBER OF HEADERS
378      */
379     nhdr = tvb_get_ntohs(tvb, pos);
380     if (ajp13_tree)
381       proto_tree_add_item(ajp13_tree, hf_ajp13_nhdr, tvb, pos, 2, ENC_BIG_ENDIAN);
382     pos+=2;
383
384     /* HEADERS
385      */
386     for(i=0; i<nhdr; i++) {
387
388       guint8 hcd;
389       guint8 hid;
390       const gchar *hval;
391       guint16 hval_len, hname_len;
392       const gchar* hname = NULL;
393       int hpos = pos;
394       /* int cl = 0; TODO: Content-Length header (encoded by 0x08) is special */
395
396       /* HEADER CODE/NAME
397        */
398       hcd = tvb_get_guint8(tvb, pos);
399
400       if (hcd == 0xA0) {
401         pos+=1;
402         hid = tvb_get_guint8(tvb, pos);
403         pos+=1;
404
405         if (hid >= array_length(rsp_headers))
406           hid = 0;
407
408         hval = ajp13_get_nstring(tvb, pos, &hval_len);
409
410         proto_tree_add_string_format_value(ajp13_tree, *rsp_headers[hid],
411                                        tvb, hpos, 2+hval_len+2, hval,
412                                        "%s", hval);
413         pos+=hval_len+2;
414 #if 0
415         /* TODO: Content-Length header (encoded by 0x08) is special */
416         if (hid == 0x08)
417           cl = 1;
418 #endif
419       } else {
420         hname = ajp13_get_nstring(tvb, pos, &hname_len);
421         pos+=hname_len+2;
422
423         hval = ajp13_get_nstring(tvb, pos, &hval_len);
424
425         proto_tree_add_string_format(ajp13_tree, hf_ajp13_additional_header,
426                                 tvb, hpos, hname_len+2+hval_len+2,
427                                 wmem_strdup_printf(wmem_packet_scope(), "%s: %s", hname, hval),
428                                 "%s: %s", hname, hval);
429         pos+=hval_len+2;
430       }
431     }
432     break;
433   }
434
435   case MTYPE_GET_BODY_CHUNK:
436   {
437     guint16 rlen;
438     rlen = tvb_get_ntohs(tvb, pos);
439     cd->content_length = rlen;
440     if (ajp13_tree)
441       proto_tree_add_item(ajp13_tree, hf_ajp13_rlen, tvb, pos, 2, ENC_BIG_ENDIAN);
442     /*pos+=2;*/
443     break;
444   }
445
446   case MTYPE_CPONG:
447     break;
448
449   default:
450     /* MESSAGE DATA (COPOUT)
451      */
452     if (ajp13_tree)
453       proto_tree_add_item(ajp13_tree, hf_ajp13_data,  tvb, pos+2, -1, ENC_UTF_8|ENC_NA);
454     break;
455   }
456 }
457
458
459
460 /* dissect a request body. see AJPv13.html, but the idea is that these
461  * packets, unlike all other packets, have no type field. you just
462  * sort of have to know that they're coming based on the previous
463  * packets.
464  */
465 static void
466 display_req_body(tvbuff_t *tvb, proto_tree *ajp13_tree, ajp13_conv_data* cd)
467 {
468   /*printf("ajp13:display_req_body()\n");*/
469   /*
470    * In a resued connection this is never reset.
471    */
472   guint16 content_length;
473   guint16 packet_length;
474
475   int pos = 0;
476
477   /* MAGIC
478    */
479   proto_tree_add_item(ajp13_tree, hf_ajp13_magic, tvb, pos, 2, ENC_NA);
480   pos+=2;
481
482   /* PACKET LENGTH
483    */
484   packet_length = tvb_get_ntohs(tvb, pos);
485   proto_tree_add_item(ajp13_tree, hf_ajp13_len, tvb, pos, 2, ENC_BIG_ENDIAN);
486   pos+=2;
487
488   if (packet_length == 0)
489   {
490     /*
491      * We've got an empty packet:
492      * 0x12 0x34 0x00 0x00
493      * It signals that there is no more data in the body
494      */
495     cd->content_length = 0;
496     return;
497   }
498
499   /* BODY (AS STRING)
500    */
501   content_length = tvb_get_ntohs( tvb, pos);
502   if (content_length == 0) {
503     /* zero length content also signals no more body data */
504     cd->content_length = 0;
505     return;
506   }
507   cd->content_length -= content_length;
508   proto_tree_add_item(ajp13_tree, hf_ajp13_data, tvb, pos+2, content_length, ENC_UTF_8|ENC_NA);
509 }
510
511
512
513 /* note that even if ajp13_tree is null on the first pass, we still
514  * need to dissect the packet in order to determine if there is a
515  * content-length, and thus if there is a subsequent automatic
516  * request-body transmitted in the next request packet. if there is a
517  * content-length, we record the fact in the conversation context.
518  * ref the top of this file for comments explaining the multi-pass
519  * thing.
520 */
521 static void
522 display_req_forward(tvbuff_t *tvb, packet_info *pinfo,
523                     proto_tree *ajp13_tree,
524                     ajp13_conv_data* cd)
525 {
526   int pos = 0;
527   guint8 meth;
528   guint8 cod;
529   const gchar *ver;
530   guint16 ver_len;
531   const gchar *uri;
532   guint16 uri_len;
533   const gchar *raddr;
534   guint16 raddr_len;
535   const gchar *rhost;
536   guint16 rhost_len;
537   const gchar *srv;
538   guint16 srv_len;
539   guint nhdr;
540   guint i;
541
542   if (ajp13_tree)
543     proto_tree_add_item(ajp13_tree, hf_ajp13_magic, tvb, pos, 2, ENC_NA);
544   pos+=2;
545
546   if (ajp13_tree)
547     proto_tree_add_item(ajp13_tree, hf_ajp13_len, tvb, pos, 2, ENC_BIG_ENDIAN);
548   pos+=2;
549
550   /* PACKET CODE
551    */
552   cod = tvb_get_guint8(tvb, 4);
553   if (ajp13_tree)
554     proto_tree_add_item(ajp13_tree, hf_ajp13_code, tvb, pos, 1, ENC_BIG_ENDIAN);
555   pos+=1;
556   if ( cod == MTYPE_CPING ) {
557     col_append_str(pinfo->cinfo, COL_INFO, "CPING" );
558     return;
559   }
560
561   /* HTTP METHOD (ENCODED AS INTEGER)
562    */
563   meth = tvb_get_guint8(tvb, pos);
564   col_append_str(pinfo->cinfo, COL_INFO, val_to_str(meth, http_method_codes, "Unknown method %u"));
565   if (ajp13_tree)
566     proto_tree_add_item(ajp13_tree, hf_ajp13_method, tvb, pos, 1, ENC_BIG_ENDIAN);
567   pos+=1;
568
569   /* HTTP VERSION STRING
570    */
571   ver = ajp13_get_nstring(tvb, pos, &ver_len);
572   if (ajp13_tree)
573     proto_tree_add_string(ajp13_tree, hf_ajp13_ver, tvb, pos, ver_len+2, ver);
574   pos=pos+ver_len+2;  /* skip over size + chars + trailing null */
575
576   /* URI
577    */
578   uri = ajp13_get_nstring(tvb, pos, &uri_len);
579   if (ajp13_tree)
580     proto_tree_add_string(ajp13_tree, hf_ajp13_uri, tvb, pos, uri_len+2, uri);
581   pos=pos+uri_len+2;  /* skip over size + chars + trailing null */
582
583
584   col_append_fstr(pinfo->cinfo, COL_INFO, " %s %s", uri, ver);
585
586
587   /* REMOTE ADDRESS
588    */
589   raddr = ajp13_get_nstring(tvb, pos, &raddr_len);
590   if (ajp13_tree)
591     proto_tree_add_string(ajp13_tree, hf_ajp13_raddr, tvb, pos, raddr_len+2, raddr);
592   pos=pos+raddr_len+2;  /* skip over size + chars + trailing null */
593
594   /* REMOTE HOST
595    */
596   rhost = ajp13_get_nstring(tvb, pos, &rhost_len);
597   if (ajp13_tree)
598     proto_tree_add_string(ajp13_tree, hf_ajp13_rhost, tvb, pos, rhost_len+2, rhost);
599   pos=pos+rhost_len+2;  /* skip over size + chars + trailing null */
600
601   /* SERVER NAME
602    */
603   srv = ajp13_get_nstring(tvb, pos, &srv_len);
604   if (ajp13_tree)
605     proto_tree_add_string(ajp13_tree, hf_ajp13_srv, tvb, pos, srv_len+2, srv);
606   pos=pos+srv_len+2;  /* skip over size + chars + trailing null */
607
608   /* SERVER PORT
609    */
610   if (ajp13_tree)
611     proto_tree_add_item(ajp13_tree, hf_ajp13_port, tvb, pos, 2, ENC_BIG_ENDIAN);
612   pos+=2;
613
614   /* IS SSL?
615    */
616   if (ajp13_tree)
617     proto_tree_add_item(ajp13_tree, hf_ajp13_sslp, tvb, pos, 1, ENC_NA);
618   pos+=1;
619
620   /* NUM HEADERS
621    */
622   nhdr = tvb_get_ntohs(tvb, pos);
623
624   if (ajp13_tree)
625     proto_tree_add_item(ajp13_tree, hf_ajp13_nhdr, tvb, pos, 2, ENC_BIG_ENDIAN);
626   pos+=2;
627   cd->content_length = 0;
628
629   /* HEADERS
630    */
631   for(i=0; i<nhdr; i++) {
632
633     guint8 hcd;
634     guint8 hid = 0;
635     const gchar* hname = NULL;
636     int hpos = pos;
637     const gchar *hval;
638     guint16 hval_len, hname_len;
639
640     /* HEADER CODE/NAME
641      */
642     hcd = tvb_get_guint8(tvb, pos);
643
644     if (hcd == 0xA0) {
645       proto_item* pi;
646
647       pos+=1;
648       hid = tvb_get_guint8(tvb, pos);
649       pos+=1;
650
651       if (hid >= array_length(req_headers))
652         hid = 0;
653
654       hval = ajp13_get_nstring(tvb, pos, &hval_len);
655
656       pi = proto_tree_add_string_format(ajp13_tree, *req_headers[hid],
657                                      tvb, hpos, 2+hval_len+2, hval,
658                                      "%s", hval);
659
660       if (hid == 0x08 && !ws_strtou32(hval, NULL, &cd->content_length)) {
661         expert_add_info(pinfo, pi, &ei_ajp13_content_length_invalid);
662       }
663
664       pos+=hval_len+2;
665     } else {
666       hname = ajp13_get_nstring(tvb, pos, &hname_len);
667       pos+=hname_len+2;
668
669       hval = ajp13_get_nstring(tvb, pos, &hval_len);
670
671       proto_tree_add_string_format(ajp13_tree, hf_ajp13_additional_header,
672                                      tvb, hpos, hname_len+2+hval_len+2,
673                                      wmem_strdup_printf(wmem_packet_scope(), "%s: %s", hname, hval),
674                                      "%s: %s", hname, hval);
675       pos+=hval_len+2;
676     }
677   }
678
679   /* ATTRIBUTES
680    */
681   while(tvb_reported_length_remaining(tvb, pos) > 0) {
682     guint8 aid;
683     const gchar* aname = NULL;
684     const gchar* aval;
685     guint16 aval_len, aname_len, key_len;
686
687     int apos = pos;
688
689     /* ATTRIBUTE CODE/NAME
690      */
691     aid = tvb_get_guint8(tvb, pos);
692     pos+=1;
693
694     if (aid == 0xFF) {
695       /* request terminator */
696       break;
697     }
698     if (aid == 0x0A) {
699       /* req_attribute - name and value follow */
700
701       aname = ajp13_get_nstring(tvb, pos, &aname_len);
702       pos+=aname_len+2;
703
704       aval = ajp13_get_nstring(tvb, pos, &aval_len);
705       pos+=aval_len+2;
706
707       proto_tree_add_string_format(ajp13_tree, hf_ajp13_req_attribute,
708                                      tvb, apos, 1+aname_len+2+aval_len+2,
709                                      wmem_strdup_printf(wmem_packet_scope(), "%s: %s", aname, aval),
710                                      "%s: %s", aname, aval);
711     } else if (aid == 0x0B ) {
712       /* ssl_key_length */
713       key_len = tvb_get_ntohs(tvb, pos);
714       proto_tree_add_uint(ajp13_tree, hf_ajp13_ssl_key_size,
715                             tvb, apos, 1+2, key_len);
716       pos+=2;
717     } else {
718
719       if (aid >= array_length(req_attributes))
720         aid = 0;
721
722       aval = ajp13_get_nstring(tvb, pos, &aval_len);
723       pos+=aval_len+2;
724
725       proto_tree_add_string_format(ajp13_tree, *req_attributes[aid],
726                                      tvb, apos, 1+aval_len+2, aval,
727                                      "%s", aval);
728     }
729   }
730 }
731
732
733
734 /* main dissector function. wireshark calls it for segments in both
735  * directions.
736  */
737 static int
738 dissect_ajp13_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
739 {
740   guint16 mag;
741   /* guint16 len; */
742   conversation_t *conv = NULL;
743   ajp13_conv_data *cd = NULL;
744   proto_tree *ajp13_tree = NULL;
745   ajp13_frame_data* fd = NULL;
746
747   /* conversational state really only does us good during the first
748    * in-order traversal
749    */
750   conv = find_or_create_conversation(pinfo);
751
752   cd = (ajp13_conv_data*)conversation_get_proto_data(conv, proto_ajp13);
753   if (!cd) {
754     cd = wmem_new(wmem_file_scope(), ajp13_conv_data);
755     cd->content_length = 0;
756     cd->was_get_body_chunk = FALSE;
757     conversation_add_proto_data(conv, proto_ajp13, cd);
758   }
759
760   /* we use the per segment user data to record the conversational
761    * state for use later on when we're called out of order (see
762    * comments at top of this file)
763    */
764   fd = (ajp13_frame_data*)p_get_proto_data(wmem_file_scope(), pinfo, proto_ajp13, 0);
765   if (!fd) {
766     /*printf("ajp13:dissect_ajp13_common():no frame data, adding");*/
767     /* since there's no per-packet user data, this must be the first
768      * time we've see the packet, and it must be the first "in order"
769      * pass through the data.
770      */
771     fd = wmem_new(wmem_file_scope(), ajp13_frame_data);
772     p_add_proto_data(wmem_file_scope(), pinfo, proto_ajp13, 0, fd);
773     fd->is_request_body = FALSE;
774     if (cd->content_length) {
775       /* this is screwy, see AJPv13.html. the idea is that if the
776        * request has a body (as determined by the content-length
777        * header), then there's always an immediate follow-up PDU with
778        * no GET_BODY_CHUNK from the container.
779        */
780       fd->is_request_body = TRUE;
781     }
782   }
783
784   col_clear(pinfo->cinfo, COL_INFO);
785
786   mag = tvb_get_ntohs(tvb, 0);
787   /*  len = tvb_get_ntohs(tvb, 2); */
788
789   col_set_str(pinfo->cinfo, COL_PROTOCOL, "AJP13");
790
791   if (mag == 0x1234 && !fd->is_request_body)
792     col_append_fstr(pinfo->cinfo, COL_INFO, "%d:REQ:", conv->conv_index);
793   else if (mag == 0x1234 && fd->is_request_body)
794     col_append_fstr(pinfo->cinfo, COL_INFO, "%d:REQ:Body", conv->conv_index);
795   else if (mag == 0x4142)
796     col_append_fstr(pinfo->cinfo, COL_INFO, "%d:RSP:", conv->conv_index);
797   else
798     col_set_str(pinfo->cinfo, COL_INFO, "AJP13 Error?");
799
800   if (tree) {
801     proto_item *ti;
802     ti = proto_tree_add_item(tree, proto_ajp13, tvb, 0, -1, ENC_NA);
803     ajp13_tree = proto_item_add_subtree(ti, ett_ajp13);
804   }
805
806   if (mag == 0x1234) {
807
808     if (fd->is_request_body)
809       display_req_body(tvb, ajp13_tree, cd);
810     else
811       display_req_forward(tvb, pinfo, ajp13_tree, cd);
812
813   } else if (mag == 0x4142) {
814
815     display_rsp(tvb, pinfo, ajp13_tree, cd);
816
817   }
818
819   return tvb_reported_length(tvb);
820 }
821
822
823
824 /* given the first chunk of the AJP13 pdu, extract out and return the
825  * packet length. see comments in packet-tcp.c:tcp_dissect_pdus().
826  */
827 static guint
828 get_ajp13_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
829 {
830   /*guint16 magic;*/
831   guint16 plen;
832   /*magic = tvb_get_ntohs(tvb, offset); */
833   plen = tvb_get_ntohs(tvb, offset+2);
834   plen += 4;
835   return plen;
836 }
837
838
839
840 /* Code to actually dissect the packets.
841  */
842 static int
843 dissect_ajp13(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
844 {
845   /* Set up structures needed to add the protocol subtree and manage it
846    */
847   tcp_dissect_pdus(tvb, pinfo, tree,
848                    TRUE,                   /* desegment or not   */
849                    4,                      /* magic + length */
850                    get_ajp13_pdu_len,      /* use first 4, calc data len */
851                    dissect_ajp13_tcp_pdu, data); /* the naive dissector */
852
853   return tvb_reported_length(tvb);
854 }
855
856
857
858 void
859 proto_register_ajp13(void)
860 {
861   expert_module_t* expert_ajp13;
862
863   static hf_register_info hf[] = {
864     { &hf_ajp13_magic,
865       { "Magic",  "ajp13.magic", FT_BYTES, BASE_NONE, NULL, 0x0, "Magic Number",
866         HFILL }
867     },
868     { &hf_ajp13_len,
869       { "Length",  "ajp13.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Data Length",
870         HFILL }
871     },
872     { &hf_ajp13_code,
873       { "Code",  "ajp13.code", FT_UINT32, BASE_DEC, VALS(mtype_codes), 0x0, "Type Code",
874          HFILL }
875     },
876     { &hf_ajp13_method,
877       { "Method",  "ajp13.method", FT_UINT8, BASE_DEC, VALS(http_method_codes), 0x0, "HTTP Method",
878         HFILL }
879     },
880     { &hf_ajp13_ver,
881       { "Version",  "ajp13.ver", FT_STRING, BASE_NONE, NULL, 0x0, "HTTP Version",
882         HFILL }
883     },
884     { &hf_ajp13_uri,
885       { "URI",  "ajp13.uri", FT_STRING, BASE_NONE, NULL, 0x0, "HTTP URI",
886         HFILL }
887     },
888     { &hf_ajp13_raddr,
889       { "RADDR",  "ajp13.raddr", FT_STRING, BASE_NONE, NULL, 0x0, "Remote Address",
890         HFILL }
891     },
892     { &hf_ajp13_rhost,
893       { "RHOST",  "ajp13.rhost", FT_STRING, BASE_NONE, NULL, 0x0, "Remote Host",
894         HFILL }
895     },
896     { &hf_ajp13_srv,
897       { "SRV",  "ajp13.srv", FT_STRING, BASE_NONE, NULL, 0x0, "Server",
898         HFILL }
899     },
900     { &hf_ajp13_port,
901       { "PORT",  "ajp13.port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL,
902         HFILL }
903     },
904     { &hf_ajp13_sslp,
905       { "SSLP",  "ajp13.sslp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Is SSL?",
906         HFILL }
907     },
908     { &hf_ajp13_nhdr,
909       { "NHDR",  "ajp13.nhdr", FT_UINT16, BASE_DEC, NULL, 0x0, "Num Headers",
910         HFILL }
911     },
912 /* response headers */
913     { &hf_ajp13_unknown_header,
914       { "unknown_header",  "ajp13.unknown_header", FT_STRING, BASE_NONE, NULL, 0x0, "Unknown Header Type",
915         HFILL }
916     },
917     { &hf_ajp13_additional_header,
918       { "additional_header",  "ajp13.additional_header", FT_STRING, BASE_NONE, NULL, 0x0, "Additional Header Type",
919         HFILL }
920     },
921     { &hf_ajp13_content_type,
922       { "Content-Type",  "ajp13.content_type", FT_STRING, BASE_NONE, NULL, 0x0, "Content-Type Header",
923         HFILL }
924     },
925     { &hf_ajp13_content_language,
926       { "Content-Language",  "ajp13.content_language", FT_STRING, BASE_NONE, NULL, 0x0, "Content-Language Header",
927         HFILL }
928     },
929     { &hf_ajp13_content_length,
930       { "Content-Length",  "ajp13.content_length", FT_STRING, BASE_NONE, NULL, 0x0, "Content-Length header",
931         HFILL }
932     },
933     { &hf_ajp13_date,
934       { "Date",  "ajp13.date", FT_STRING, BASE_NONE, NULL, 0x0, "Date Header",
935         HFILL }
936     },
937     { &hf_ajp13_last_modified,
938       { "Last-Modified",  "ajp13.last_modified", FT_STRING, BASE_NONE, NULL, 0x0, "Last Modified Header",
939         HFILL }
940     },
941     { &hf_ajp13_location,
942       { "Location",  "ajp13.location", FT_STRING, BASE_NONE, NULL, 0x0, "Location Header",
943         HFILL }
944     },
945     { &hf_ajp13_set_cookie,
946       { "Set-Cookie",  "ajp13.set_cookie", FT_STRING, BASE_NONE, NULL, 0x0, "Set-Cookie Header",
947         HFILL }
948     },
949     { &hf_ajp13_set_cookie2,
950       { "Set-Cookie2",  "ajp13.set_cookie2", FT_STRING, BASE_NONE, NULL, 0x0, "Set-Cookie2 Header",
951         HFILL }
952     },
953     { &hf_ajp13_servlet_engine,
954       { "Servlet-Engine",  "ajp13.servlet_engine", FT_STRING, BASE_NONE, NULL, 0x0, "Servlet-Engine Header",
955         HFILL }
956     },
957     { &hf_ajp13_status,
958       { "Status",  "ajp13.status", FT_STRING, BASE_NONE, NULL, 0x0, "Status Header",
959         HFILL }
960     },
961     { &hf_ajp13_www_authenticate,
962       { "WWW-Authenticate",  "ajp13.www_authenticate", FT_STRING, BASE_NONE, NULL, 0x0, "WWW-Authenticate Header",
963         HFILL }
964     },
965 /* request headers */
966     { &hf_ajp13_accept,
967       { "Accept",  "ajp13.accept", FT_STRING, BASE_NONE, NULL, 0x0, "Accept Header",
968         HFILL }
969     },
970     { &hf_ajp13_accept_charset,
971       { "Accept-Charset",  "ajp13.accept_charset", FT_STRING, BASE_NONE, NULL, 0x0, "Accept-Charset Header",
972         HFILL }
973     },
974     { &hf_ajp13_accept_encoding,
975       { "Accept-Encoding",  "ajp13.accept_encoding", FT_STRING, BASE_NONE, NULL, 0x0, "Accept-Encoding Header",
976         HFILL }
977     },
978     { &hf_ajp13_accept_language,
979       { "Accept-Language",  "ajp13.accept_language", FT_STRING, BASE_NONE, NULL, 0x0, "Accept-Language Header",
980         HFILL }
981     },
982     { &hf_ajp13_authorization,
983       { "Authorization",  "ajp13.authorization", FT_STRING, BASE_NONE, NULL, 0x0, "Authorization Header",
984         HFILL }
985     },
986     { &hf_ajp13_connection,
987       { "Connection",  "ajp13.connection", FT_STRING, BASE_NONE, NULL, 0x0, "Connection Header",
988         HFILL }
989     },
990     { &hf_ajp13_cookie,
991       { "Cookie",  "ajp13.cookie", FT_STRING, BASE_NONE, NULL, 0x0, "Cookie Header",
992         HFILL }
993     },
994     { &hf_ajp13_cookie2,
995       { "Cookie2",  "ajp13.cookie2", FT_STRING, BASE_NONE, NULL, 0x0, "Cookie2 Header",
996         HFILL }
997     },
998     { &hf_ajp13_host,
999       { "Host",  "ajp13.host", FT_STRING, BASE_NONE, NULL, 0x0, "Host Header",
1000         HFILL }
1001     },
1002     { &hf_ajp13_pragma,
1003       { "Pragma",  "ajp13.pragma", FT_STRING, BASE_NONE, NULL, 0x0, "Pragma Header",
1004         HFILL }
1005     },
1006     { &hf_ajp13_referer,
1007       { "Referer",  "ajp13.referer", FT_STRING, BASE_NONE, NULL, 0x0, "Referer Header",
1008         HFILL }
1009     },
1010     { &hf_ajp13_user_agent,
1011       { "User-Agent",  "ajp13.user_agent", FT_STRING, BASE_NONE, NULL, 0x0, "User-Agent Header",
1012         HFILL }
1013     },
1014 /* request attributes */
1015     { &hf_ajp13_unknown_attribute,
1016       { "unknown_attribute",  "ajp13.unknown_attribute", FT_STRING, BASE_NONE, NULL, 0x0, "Unknown Attribute Type",
1017         HFILL }
1018     },
1019     { &hf_ajp13_req_attribute,
1020       { "req_attribute",  "ajp13.req_attribute", FT_STRING, BASE_NONE, NULL, 0x0, "Additional Attribute Type",
1021         HFILL }
1022     },
1023     { &hf_ajp13_context,
1024       { "Context",  "ajp13.context", FT_STRING, BASE_NONE, NULL, 0x0, "Context Attribute",
1025         HFILL }
1026     },
1027     { &hf_ajp13_servlet_path,
1028       { "Servlet-Path",  "ajp13.servlet_path", FT_STRING, BASE_NONE, NULL, 0x0, "Servlet-Path Attribute",
1029         HFILL }
1030     },
1031     { &hf_ajp13_remote_user,
1032       { "Remote-User",  "ajp13.remote_user", FT_STRING, BASE_NONE, NULL, 0x0, "Remote-User Attribute",
1033         HFILL }
1034     },
1035     { &hf_ajp13_auth_type,
1036       { "Auth-Type",  "ajp13.auth_type", FT_STRING, BASE_NONE, NULL, 0x0, "Auth-Type Attribute",
1037         HFILL }
1038     },
1039     { &hf_ajp13_query_string,
1040       { "Query-String",  "ajp13.query_string", FT_STRING, BASE_NONE, NULL, 0x0, "Query-String Attribute",
1041         HFILL }
1042     },
1043     { &hf_ajp13_route,
1044       { "Route",  "ajp13.route", FT_STRING, BASE_NONE, NULL, 0x0, "Route Attribute",
1045         HFILL }
1046     },
1047     { &hf_ajp13_ssl_cert,
1048       { "SSL-Cert",  "ajp13.ssl_cert", FT_STRING, BASE_NONE, NULL, 0x0, "SSL-Cert Attribute",
1049         HFILL }
1050     },
1051     { &hf_ajp13_ssl_cipher,
1052       { "SSL-Cipher",  "ajp13.ssl_cipher", FT_STRING, BASE_NONE, NULL, 0x0, "SSL-Cipher Attribute",
1053         HFILL }
1054     },
1055     { &hf_ajp13_ssl_session,
1056       { "SSL-Session",  "ajp13.ssl_session", FT_STRING, BASE_NONE, NULL, 0x0, "SSL-Session Attribute",
1057         HFILL }
1058     },
1059     { &hf_ajp13_ssl_key_size,
1060       { "SSL-Key-Size",  "ajp13.ssl_key_size", FT_UINT16, BASE_DEC, NULL, 0x0, "SSL-Key-Size Attribute",
1061         HFILL }
1062     },
1063     { &hf_ajp13_secret,
1064       { "Secret",  "ajp13.secret", FT_STRING, BASE_NONE, NULL, 0x0, "Secret Attribute",
1065         HFILL }
1066     },
1067     { &hf_ajp13_stored_method,
1068       { "Stored-Method",  "ajp13.stored_method", FT_STRING, BASE_NONE, NULL, 0x0, "Stored-Method Attribute",
1069         HFILL }
1070     },
1071
1072     { &hf_ajp13_rlen,
1073       { "RLEN",  "ajp13.rlen", FT_UINT16, BASE_DEC, NULL, 0x0, "Requested Length",
1074         HFILL }
1075     },
1076     { &hf_ajp13_reusep,
1077       { "REUSEP",  "ajp13.reusep", FT_UINT8, BASE_DEC, NULL, 0x0, "Reuse Connection?",
1078         HFILL }
1079     },
1080     { &hf_ajp13_rstatus,
1081       { "RSTATUS",  "ajp13.rstatus", FT_UINT16, BASE_DEC, NULL, 0x0, "HTTP Status Code",
1082         HFILL }
1083     },
1084     { &hf_ajp13_rsmsg,
1085       { "RSMSG",  "ajp13.rmsg", FT_STRING, BASE_NONE, NULL, 0x0, "HTTP Status Message",
1086         HFILL }
1087     },
1088     { &hf_ajp13_data,
1089       { "Data",  "ajp13.data", FT_STRING, BASE_NONE, NULL, 0x0, NULL,
1090         HFILL }
1091     },
1092   };
1093
1094   static ei_register_info ei[] = {
1095     { &ei_ajp13_content_length_invalid, { "ajp13.content_length.invalid", PI_MALFORMED, PI_ERROR,
1096       "Content-Length must be a string containing an integer", EXPFILL }}
1097   };
1098
1099   static gint *ett[] = {
1100     &ett_ajp13,
1101   };
1102
1103   /* Register the protocol name and description
1104    */
1105   proto_ajp13 = proto_register_protocol("Apache JServ Protocol v1.3", "AJP13", "ajp13");
1106
1107   proto_register_field_array(proto_ajp13, hf, array_length(hf));
1108   proto_register_subtree_array(ett, array_length(ett));
1109
1110   expert_ajp13 = expert_register_protocol(proto_ajp13);
1111   expert_register_field_array(expert_ajp13, ei, array_length(ei));
1112 }
1113
1114
1115
1116 void
1117 proto_reg_handoff_ajp13(void)
1118 {
1119   dissector_handle_t ajp13_handle;
1120   ajp13_handle = create_dissector_handle(dissect_ajp13, proto_ajp13);
1121   dissector_add_uint_with_preference("tcp.port", AJP13_TCP_PORT, ajp13_handle);
1122 }
1123
1124 /*
1125  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1126  *
1127  * Local Variables:
1128  * c-basic-offset: 2
1129  * tab-width: 8
1130  * indent-tabs-mode: nil
1131  * End:
1132  *
1133  * ex: set shiftwidth=2 tabstop=8 expandtab:
1134  * :indentSize=2:tabSize=8:noTabs=true:
1135  */