http2: mimic HTTP1 request from upgrade

pull/5403/head
Philippe Antoine 5 years ago committed by Victor Julien
parent 9d1b030ff0
commit 7011bddf84

@ -15,9 +15,12 @@
* 02110-1301, USA.
*/
use super::http2::{HTTP2FrameTypeData, HTTP2Transaction};
use super::http2::{
HTTP2Frame, HTTP2FrameTypeData, HTTP2State, HTTP2Transaction, HTTP2TransactionState,
};
use super::parser;
use crate::core::STREAM_TOSERVER;
use crate::log::*;
use std::ffi::CStr;
use std::mem::transmute;
use std::str::FromStr;
@ -544,3 +547,61 @@ pub unsafe extern "C" fn rs_http2_tx_get_header(
return 0;
}
fn http2_tx_set_header(state: &mut HTTP2State, name: &[u8], input: &[u8]) {
let head = parser::HTTP2FrameHeader {
length: 0,
ftype: parser::HTTP2FrameType::HEADERS as u8,
flags: 0,
reserved: 0,
stream_id: 1,
};
let mut blocks = Vec::new();
let b = parser::HTTP2FrameHeaderBlock {
name: name.to_vec(),
value: input.to_vec(),
error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
sizeupdate: 0,
};
blocks.push(b);
let hs = parser::HTTP2FrameHeaders {
padlength: None,
priority: None,
blocks: blocks,
};
let txdata = HTTP2FrameTypeData::HEADERS(hs);
let tx = state.find_or_create_tx(&head, &txdata, STREAM_TOSERVER);
tx.frames_ts.push(HTTP2Frame {
header: head,
data: txdata,
});
//we do not expect more data from client
tx.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
}
#[no_mangle]
pub extern "C" fn rs_http2_tx_set_method(
state: &mut HTTP2State, buffer: *const u8, buffer_len: u32,
) {
let slice = build_slice!(buffer, buffer_len as usize);
http2_tx_set_header(state, ":method".as_bytes(), slice)
}
#[no_mangle]
pub extern "C" fn rs_http2_tx_set_uri(state: &mut HTTP2State, buffer: *const u8, buffer_len: u32) {
let slice = build_slice!(buffer, buffer_len as usize);
http2_tx_set_header(state, ":path".as_bytes(), slice)
}
#[no_mangle]
pub extern "C" fn rs_http2_tx_add_header(
state: &mut HTTP2State, name: *const u8, name_len: u32, value: *const u8, value_len: u32,
) {
let slice_name = build_slice!(name, name_len as usize);
let slice_value = build_slice!(value, value_len as usize);
if slice_name == "HTTP2-Settings".as_bytes() {
SCLogNotice!("lol seetings TODO");
} else {
http2_tx_set_header(state, slice_name, slice_value)
}
}

@ -117,7 +117,7 @@ pub struct HTTP2Frame {
pub struct HTTP2Transaction {
tx_id: u64,
pub stream_id: u32,
state: HTTP2TransactionState,
pub state: HTTP2TransactionState,
child_stream_id: u32,
pub frames_tc: Vec<HTTP2Frame>,
@ -373,7 +373,7 @@ impl HTTP2State {
return self.transactions.last_mut().unwrap();
}
fn find_or_create_tx(
pub fn find_or_create_tx(
&mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: u8,
) -> &mut HTTP2Transaction {
if header.stream_id == 0 {
@ -876,11 +876,27 @@ pub extern "C" fn rs_http2_probing_parser_tc(
return ALPROTO_UNKNOWN;
}
/// Extern functions operating on HTTP2.
extern "C" {
pub fn HTTP2MimicHttp1Request(
orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void,
);
}
#[no_mangle]
pub extern "C" fn rs_http2_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
pub extern "C" fn rs_http2_state_new(
orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
) -> *mut std::os::raw::c_void {
let state = HTTP2State::new();
let boxed = Box::new(state);
return unsafe { transmute(boxed) };
let r = unsafe { transmute(boxed) };
if orig_state != std::ptr::null_mut() {
//we could check ALPROTO_HTTP == orig_proto
unsafe {
HTTP2MimicHttp1Request(orig_state, r);
}
}
return r;
}
#[no_mangle]

@ -968,13 +968,6 @@ static AppLayerResult HTPHandleResponseData(Flow *f, void *htp_state,
}
consumed = htp_connp_res_data_consumed(hstate->connp);
AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_HTTP2);
// close connection to log HTTP1 request in tunnel mode
if (!(hstate->flags & HTP_FLAG_STATE_CLOSED_TC)) {
htp_connp_close(hstate->connp, &ts);
hstate->flags |= HTP_FLAG_STATE_CLOSED_TC;
}
// TODO mimic HTTP1 request into HTTP2
// During HTTP2 upgrade, we may consume the HTTP1 part of the data
// and we need to parser the remaining part with HTTP2
if (consumed > 0 && consumed < input_len) {
@ -2958,6 +2951,19 @@ static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
return NULL;
}
void *HtpGetTxForH2(void *alstate)
{
// gets last transaction
HtpState *http_state = (HtpState *)alstate;
if (http_state != NULL && http_state->conn != NULL) {
size_t txid = htp_list_array_size(http_state->conn->transactions);
if (txid > 0) {
return htp_list_get(http_state->conn->transactions, txid - 1);
}
}
return NULL;
}
static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction)
{
return (direction & STREAM_TOSERVER) ? HTP_REQUEST_COMPLETE : HTP_RESPONSE_COMPLETE;

@ -288,6 +288,8 @@ void HTPConfigure(void);
void HtpConfigCreateBackup(void);
void HtpConfigRestoreBackup(void);
void *HtpGetTxForH2(void *);
#endif /* __APP_LAYER_HTP_H__ */
/**

@ -32,6 +32,7 @@
#include "app-layer-detect-proto.h"
#include "app-layer-parser.h"
#include "app-layer-htp.h"
#include "app-layer-http2.h"
#include "rust.h"
@ -69,3 +70,22 @@ void RegisterHTTP2Parsers(void)
//TODOask HTTP2ParserRegisterTests();
#endif
}
void HTTP2MimicHttp1Request(void *alstate_orig, void *h2s)
{
htp_tx_t *h1tx = HtpGetTxForH2(alstate_orig);
if (h2s == NULL || h1tx == NULL) {
return;
}
rs_http2_tx_set_method(h2s, bstr_ptr(h1tx->request_method), bstr_len(h1tx->request_method));
rs_http2_tx_set_uri(h2s, bstr_ptr(h1tx->request_uri), bstr_len(h1tx->request_uri));
size_t nbheaders = htp_table_size(h1tx->request_headers);
for (size_t i = 0; i < nbheaders; i++) {
htp_header_t *h = htp_table_get_index(h1tx->request_headers, i, NULL);
if (h != NULL) {
rs_http2_tx_add_header(h2s, bstr_ptr(h->name), bstr_len(h->name), bstr_ptr(h->value),
bstr_len(h->value));
}
}
}

@ -26,4 +26,6 @@
void RegisterHTTP2Parsers(void);
void HTTP2MimicHttp1Request(void *, void *);
#endif /* __APP_LAYER_HTTP2_H__ */

Loading…
Cancel
Save