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