IPP: Support both IPP and IPPS

IPP uses the same well known TCP port, 631, for running atop HTTP
(which can upgrade to TLS, RFC 2817) as well as connections that
start out as HTTP over TLS (IPPS, RFC 7472). RFC 8010 notes that
HTTP/2 is also an OPTIONAL transport type.

Despite the clear admonition of RFC 8010 that:
    the "Content-Type" of the message body in each request and response
    MUST be "application/ipp"
many IPP implementations (e.g., on HP printers) often fail to include the
Content-Type in their chunked responses.

So we register IPP in the HTTP port-based dissector so that packets
without a Content-Type will still call the IPP dissector. (Note that
IPP servers commonly will respond to normal HTTP and HTTPS requests
on port 631 just as they would on port 80 or 443, which is why it is
good that we check the Content-Type first. At least those non-IPP
requests and responses seem always to have the Content-Type.)

We can only have a single dissector in the TCP dissector table for port
631. If we don't register a fake helper protocol that tries TLS, HTTP/2,
and HTTP in order, then the others will be recognized heuristically. For
now at least, we are better off having TLS be the dissector set to the port,
because the non-heuristic HTTP dissector never rejects packets. Even when
a packet doesn't look like HTTP and HTTP has never been seen, so the HTTP
dissector doesn't add anything to the tree, it still claims to consume all
the bytes.

When TCP calls a heuristic dissector, pinfo->match_uint does not get
set. If pinfo->match_uint is neither the source nor destination port
(and thus is probably set to IP_PROTO_TCP by the IP dissector), check
the HTTP port subdissector table using the source or destination port,
depending upon whether we have a request or a response.

Fix #18825
This commit is contained in:
John Thacker 2023-01-31 21:35:35 -05:00
parent 8ecb0b53f2
commit 4b377dd250
2 changed files with 50 additions and 3 deletions

View File

@ -2209,8 +2209,25 @@ dissecting_body:
* a media type and instead use a specified port.
*/
if (handle == NULL) {
handle = dissector_get_uint_handle(port_subdissector_table,
pinfo->match_uint);
/* If the HTTP dissector was called heuristically
* (or the HTTP dissector was called from the TLS
* dissector, which was called heuristically), then
* match_uint doesn't get set (or is likely set to
* 6 for IP_PROTO_TCP.) Some protocols (e.g., IPP)
* use the same specified port for both HTTP and
* HTTP over TLS, and one will be a heuristic match.
* In those cases, look at the src or dest port.
*/
if (pinfo->match_uint == pinfo->srcport || pinfo->match_uint == pinfo->destport) {
handle = dissector_get_uint_handle(port_subdissector_table,
pinfo->match_uint);
} else if (http_type == MEDIA_CONTAINER_HTTP_REQUEST) {
handle = dissector_get_uint_handle(port_subdissector_table,
pinfo->destport);
} else if (http_type == MEDIA_CONTAINER_HTTP_RESPONSE) {
handle = dissector_get_uint_handle(port_subdissector_table,
pinfo->srcport);
}
}
if (handle != NULL) {
@ -3976,6 +3993,10 @@ dissect_http_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
end_of_stream = (tcpinfo && IS_TH_FIN(tcpinfo->flags));
dissect_http_on_stream(tvb, pinfo, tree, conv_data, end_of_stream, tcpinfo ? &tcpinfo->seq : NULL);
/* XXX - If we haven't seen any HTTP yet even after dissecting above,
* should we return 0 here so that heuristic dissectors can get a
* chance?
*/
return tvb_captured_length(tvb);
}

View File

@ -22,6 +22,7 @@
#include <epan/wmem_scopes.h>
#include "packet-http.h"
#include "packet-media-type.h"
#include "packet-tls.h"
void proto_register_ipp(void);
void proto_reg_handoff_ipp(void);
@ -1585,9 +1586,34 @@ void
proto_reg_handoff_ipp(void)
{
/*
* Register ourselves as running atop HTTP and using port 631.
* IPP uses the same well-known TCP port, 631, for both running atop HTTP
* and atop HTTP over TLS (IPPS, RFC 7472). The latter includes both
* connections that start out as HTTP and upgrade to using TLS (RFC 2817)
* as well as connections that begin as TLS. Despite RFC 8010:
* the "Content-Type" of the message body in each request and response
* MUST be "application/ipp"
* a number of implementations fail to include the Content-Type in their
* chunked responses. (#18825, #5718, #6765).
*
* For that reason, we register IPP in the HTTP port-based dissector so
* that packets without a Content-Type on port 631 will use this dissector.
* (RFC 8010 also notes that HTTP/2 is an OPTIONAL transport layer; we
* don't have a port-based dissector dissector for HTTP/2, but hopefully
* any implementations that use HTTP/2 always send the Content-Type.)
* Note we check for port-based dissectors after the Content-Type; this
* is good because many IPP servers will respond to non-IPP HTTP requests
* on port 631 just as they would on ports 80 or 443.
*
* We can only have a single dissector in the TCP dissector table for
* port 631. If we don't register a fake helper protocol that tries
* each of TLS, HTTP/2, and HTTP in order (cf. #16541, #18016), we're
* currently better off having TLS be the registered dissector and HTTP
* be detected heuristically, because the non-heuristic HTTP dissector
* never rejects packets, even when it doesn't add anything to the tree.
*/
dissector_handle_t http_tls_handle = find_dissector_add_dependency("http-over-tls", proto_ipp);
http_tcp_dissector_add(631, ipp_handle);
ssl_dissector_add(631, http_tls_handle);
dissector_add_string("media_type", "application/ipp", ipp_handle);
}