diff options
| author | lijia <[email protected]> | 2024-10-27 18:08:00 +0800 |
|---|---|---|
| committer | lijia <[email protected]> | 2024-11-08 11:23:16 +0800 |
| commit | 627cfac992c52e3c7950355c0d447764056a5276 (patch) | |
| tree | afb5f8f462d964a764dbb071f5cfadad199cbe4d /decoders/http/http_decoder_utils.c | |
| parent | d0a868591470a4a9d71a65a5d540058e72c8d92c (diff) | |
httpv2.0 rebase onto develop-2.0dev-http-v2.0
Diffstat (limited to 'decoders/http/http_decoder_utils.c')
| -rw-r--r-- | decoders/http/http_decoder_utils.c | 536 |
1 files changed, 296 insertions, 240 deletions
diff --git a/decoders/http/http_decoder_utils.c b/decoders/http/http_decoder_utils.c index 08c66b0..6c20ce7 100644 --- a/decoders/http/http_decoder_utils.c +++ b/decoders/http/http_decoder_utils.c @@ -1,311 +1,367 @@ #include <string.h> #include <assert.h> +#include <arpa/inet.h> #include "stellar/http.h" -#include "http_decoder_private.h" +#include "stellar/utils.h" +#include "http_decoder_utils.h" +#include "http_decoder.h" +#include "llhttp.h" -char *http_safe_dup(const char *str, size_t len) +#ifdef __cplusplus +extern "C" { - if (str == NULL || len == 0) - { - return NULL; - } - char *dup = CALLOC(char, len + 1); - memcpy(dup, str, len); - return dup; -} +#endif -int http_strncasecmp_safe(const char *fix_s1, const char *dyn_s2, size_t fix_n1, size_t dyn_n2) -{ - if (fix_s1 == NULL || dyn_s2 == NULL) + char *http_safe_dup(const char *str, size_t len) { - return -1; + if (str == NULL || len == 0) + { + return NULL; + } + char *dup = CALLOC(char, len + 1); + memcpy(dup, str, len); + return dup; } - if (fix_n1 != dyn_n2) + + int http_strncasecmp_safe(const char *fix_s1, const char *dyn_s2, size_t fix_n1, size_t dyn_n2) { - return -1; + if (fix_s1 == NULL || dyn_s2 == NULL) + { + return -1; + } + if (fix_n1 != dyn_n2) + { + return -1; + } + return strncasecmp(fix_s1, dyn_s2, fix_n1); } - return strncasecmp(fix_s1, dyn_s2, fix_n1); -} -const char *http_message_type_to_string(enum http_message_type type) -{ - const char *sname = "unknown_msg_type"; - - switch (type) + const char *http_topic_type_to_string(enum http_topic_type type) { - case HTTP_MESSAGE_REQ_LINE: - sname = "HTTP_MESSAGE_REQ_LINE"; - break; - case HTTP_MESSAGE_REQ_HEADER: - sname = "HTTP_MESSAGE_REQ_HEADER"; - break; - case HTTP_MESSAGE_REQ_HEADER_END: - sname = "HTTP_MESSAGE_REQ_HEADER_END"; - break; - case HTTP_MESSAGE_REQ_BODY_START: - sname = "HTTP_MESSAGE_REQ_BODY_START"; - break; - case HTTP_MESSAGE_REQ_BODY: - sname = "HTTP_MESSAGE_REQ_BODY"; - break; - case HTTP_MESSAGE_REQ_BODY_END: - sname = "HTTP_MESSAGE_REQ_BODY_END"; - break; - case HTTP_MESSAGE_RES_LINE: - sname = "HTTP_MESSAGE_RES_LINE"; - break; - case HTTP_MESSAGE_RES_HEADER: - sname = "HTTP_MESSAGE_RES_HEADER"; - break; - case HTTP_MESSAGE_RES_HEADER_END: - sname = "HTTP_MESSAGE_RES_HEADER_END"; - break; - case HTTP_MESSAGE_RES_BODY_START: - sname = "HTTP_MESSAGE_RES_BODY_START"; - break; - case HTTP_MESSAGE_RES_BODY: - sname = "HTTP_MESSAGE_RES_BODY"; - break; - case HTTP_MESSAGE_RES_BODY_END: - sname = "HTTP_MESSAGE_RES_BODY_END"; - break; - case HTTP_TRANSACTION_START: - sname = "HTTP_TRANSACTION_START"; - break; - case HTTP_TRANSACTION_END: - sname = "HTTP_TRANSACTION_END"; - break; + const char *sname = "unknown_topic"; - default: - break; + switch (type) + { + case HTTP_TOPIC_REQ_HEADER: + sname = "HTTP_TOPIC_REQ_HEADER"; + break; + case HTTP_TOPIC_REQ_BODY: + sname = "HTTP_TOPIC_REQ_BODY"; + break; + case HTTP_TOPIC_RES_HEADER: + sname = "HTTP_TOPIC_RES_HEADER"; + break; + case HTTP_TOPIC_RES_BODY: + sname = "HTTP_TOPIC_RES_BODY"; + break; + default: + break; + } + return sname; } - return sname; -} - -int http_message_type_is_req(struct session *sess, enum http_message_type msg_type) -{ - int is_req_msg = 0; - - switch (msg_type) - { - case HTTP_MESSAGE_REQ_LINE: - case HTTP_MESSAGE_REQ_HEADER: - case HTTP_MESSAGE_REQ_HEADER_END: - case HTTP_MESSAGE_REQ_BODY_START: - case HTTP_MESSAGE_REQ_BODY: - case HTTP_MESSAGE_REQ_BODY_END: - is_req_msg = 1; - break; + static const unsigned char __g_httpd_hextable[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 10, 11, 12, 13, 14, 15 /* 0x60 - 0x66 */ + }; - case HTTP_MESSAGE_RES_LINE: - case HTTP_MESSAGE_RES_HEADER: - case HTTP_MESSAGE_RES_HEADER_END: - case HTTP_MESSAGE_RES_BODY_START: - case HTTP_MESSAGE_RES_BODY: - case HTTP_MESSAGE_RES_BODY_END: - is_req_msg = 0; - break; +/* the input is a single hex digit */ +#define onehex2dec(x) __g_httpd_hextable[x - '0'] - case HTTP_TRANSACTION_START: - case HTTP_TRANSACTION_END: +#include <ctype.h> + // https://github.com/curl/curl/blob/2e930c333658725657b94a923d175c6622e0f41d/lib/urlapi.c + // void httpd_url_decode(const char *string, size_t length, char *ostring, size_t *olen) + size_t http_url_decode(const char *string, size_t length, char *ostring, size_t olen) { - enum flow_type cur_dir = session_get_flow_type(sess); - if (FLOW_TYPE_C2S == cur_dir) + char *ns = ostring; + if (NULL == string || NULL == ostring || 0 == olen) { - is_req_msg = 1; + return 0; } - else + size_t alloc = length; + while (alloc) { - is_req_msg = 0; + unsigned char in = (unsigned char)*string; + if (('%' == in) && (alloc > 2) && + isxdigit(string[1]) && isxdigit(string[2])) + { + /* this is two hexadecimal digits following a '%' */ + in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]); + string += 3; + alloc -= 3; + } + else + { + string++; + alloc--; + } + *ns++ = (char)in; + // if ((size_t)(ns - ostring) >= olen - 1) + // { + // return 1; + // } } + return ns - ostring; } - break; - - default: - assert(0); - fprintf(stderr, "unknow message type:%d\n", (int)msg_type); - break; - } - return is_req_msg; -} -int http_event_is_req(enum http_event event) -{ - switch (event) + int httpd_url_is_encoded(const char *url, size_t len) { - case HTTP_EVENT_REQ_INIT: - case HTTP_EVENT_REQ_LINE: - case HTTP_EVENT_REQ_HDR: - case HTTP_EVENT_REQ_HDR_END: - case HTTP_EVENT_REQ_BODY_BEGIN: - case HTTP_EVENT_REQ_BODY_DATA: - case HTTP_EVENT_REQ_BODY_END: - case HTTP_EVENT_REQ_END: - return 1; - break; - - case HTTP_EVENT_RES_INIT: - case HTTP_EVENT_RES_LINE: - case HTTP_EVENT_RES_HDR: - case HTTP_EVENT_RES_HDR_END: - case HTTP_EVENT_RES_BODY_BEGIN: - case HTTP_EVENT_RES_BODY_DATA: - case HTTP_EVENT_RES_BODY_END: - case HTTP_EVENT_RES_END: + for (size_t i = 0; i < len; i++) + { + if (url[i] == '%') + { + return 1; + } + } return 0; - break; - - default: - assert(0); - fprintf(stderr, "unknow event type:%d\n", (int)event); - break; } - return -1; -} -int stellar_session_mq_get_topic_id_reliable(struct stellar *st, const char *topic_name, - stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg) -{ - int topic_id = stellar_mq_get_topic_id(st, topic_name); - if (topic_id < 0) + static void httpd_set_tcp_addr(const struct tcphdr *tcph, struct http_session_addr *addr, enum flow_type fdir) { - topic_id = stellar_mq_create_topic(st, topic_name, msg_free_cb, msg_free_arg); + if (FLOW_TYPE_C2S == fdir) + { + addr->sport = tcph->th_sport; + addr->dport = tcph->th_dport; + } + else + { + addr->sport = tcph->th_dport; + addr->dport = tcph->th_sport; + } } - return topic_id; -} - -static const unsigned char __g_httpd_hextable[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ - 0, 10, 11, 12, 13, 14, 15 /* 0x60 - 0x66 */ -}; - -/* the input is a single hex digit */ -#define onehex2dec(x) __g_httpd_hextable[x - '0'] - -#include <ctype.h> -// https://github.com/curl/curl/blob/2e930c333658725657b94a923d175c6622e0f41d/lib/urlapi.c -// void httpd_url_decode(const char *string, size_t length, char *ostring, size_t *olen) -size_t http_url_decode(const char *string, size_t length, char *ostring, size_t olen) -{ - char *ns = ostring; - if (NULL == string || NULL == ostring || 0 == olen) + static void httpd_set_ipv4_addr(const struct ip *ip4h, struct http_session_addr *addr, enum flow_type fdir) { - return 0; + addr->ipver = 4; + if (FLOW_TYPE_C2S == fdir) + { + addr->saddr4 = ip4h->ip_src.s_addr; + addr->daddr4 = ip4h->ip_dst.s_addr; + } + else + { + addr->saddr4 = ip4h->ip_dst.s_addr; + addr->daddr4 = ip4h->ip_src.s_addr; + } } - size_t alloc = length; - while (alloc) + static void httpd_set_ipv6_addr(const struct ip6_hdr *ip6h, struct http_session_addr *addr, enum flow_type fdir) { - unsigned char in = (unsigned char)*string; - if (('%' == in) && (alloc > 2) && - isxdigit(string[1]) && isxdigit(string[2])) + addr->ipver = 6; + if (FLOW_TYPE_C2S == fdir) { - /* this is two hexadecimal digits following a '%' */ - in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]); - string += 3; - alloc -= 3; + memcpy(&addr->saddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); + memcpy(&addr->daddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); } else { - string++; - alloc--; + memcpy(&addr->saddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); + memcpy(&addr->daddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); } - *ns++ = (char)in; - // if ((size_t)(ns - ostring) >= olen - 1) - // { - // return 1; - // } } - return ns - ostring; -} -int httpd_url_is_encoded(const char *url, size_t len) -{ - for (size_t i = 0; i < len; i++) + void httpd_session_get_addr(const struct session *sess, struct http_session_addr *addr) { - if (url[i] == '%') + if (sess == NULL || addr == NULL) + { + return; + } + enum flow_type fdir = session_get_flow_type(sess); + const struct packet *raw_pkt = session_get_first_packet(sess, fdir); + if (NULL == raw_pkt) { - return 1; + addr->ipver = 0; + return; + } + + int count = packet_get_layer_count(raw_pkt); + for (int i = count - 1; i >= 0; i--) + { + const struct layer *layer = packet_get_layer_by_idx(raw_pkt, i); + if (layer->proto == LAYER_PROTO_TCP) + { + httpd_set_tcp_addr(layer->hdr.tcp, addr, fdir); + } + else if (layer->proto == LAYER_PROTO_IPV4) + { + httpd_set_ipv4_addr(layer->hdr.ip4, addr, fdir); + break; + } + else if (layer->proto == LAYER_PROTO_IPV6) + { + httpd_set_ipv6_addr(layer->hdr.ip6, addr, fdir); + break; + } } } - return 0; -} -static void httpd_set_tcp_addr(const struct tcphdr *tcph, struct httpd_session_addr *addr, enum flow_type fdir) -{ - if (FLOW_TYPE_C2S == fdir) + void http_session_addr_ntop(const struct http_session_addr *sesaddr, char *buf, size_t buflen) { - addr->sport = tcph->th_sport; - addr->dport = tcph->th_dport; + char sip_str[INET6_ADDRSTRLEN] = {0}; + char dip_str[INET6_ADDRSTRLEN] = {0}; + uint16_t sport_host, dport_host; + if (sesaddr->ipver == 4) + { + inet_ntop(AF_INET, &sesaddr->saddr4, sip_str, sizeof(sip_str)); + inet_ntop(AF_INET, &sesaddr->daddr4, dip_str, sizeof(dip_str)); + } + else if (sesaddr->ipver == 6) + { + inet_ntop(AF_INET6, &sesaddr->saddr6, sip_str, sizeof(sip_str)); + inet_ntop(AF_INET6, &sesaddr->daddr6, dip_str, sizeof(dip_str)); + } + sport_host = ntohs(sesaddr->sport); + dport_host = ntohs(sesaddr->dport); + snprintf(buf, buflen, "%s:%u-%s:%u", sip_str, sport_host, dip_str, dport_host); } - else + + struct http_buffer *http_buffer_new(void) { - addr->sport = tcph->th_dport; - addr->dport = tcph->th_sport; + struct http_buffer *buffer = CALLOC(struct http_buffer, 1); + buffer->buffer = NULL; + buffer->buffer_size = 0; + buffer->reference = 1; + return buffer; } -} -static void httpd_set_ipv4_addr(const struct ip *ip4h, struct httpd_session_addr *addr, enum flow_type fdir) -{ - addr->ipver = 4; - if (FLOW_TYPE_C2S == fdir) + + void http_buffer_free(struct http_buffer *buffer) { - addr->saddr4 = ip4h->ip_src.s_addr; - addr->daddr4 = ip4h->ip_dst.s_addr; + if (NULL == buffer) + { + return; + } + if (buffer->reference > 1) + { + buffer->reference--; + return; + } + if (buffer->buffer) + { + FREE(buffer->buffer); + } + FREE(buffer); } - else + + int http_buffer_add(struct http_buffer *buffer, const char *data, size_t data_len) { - addr->saddr4 = ip4h->ip_dst.s_addr; - addr->daddr4 = ip4h->ip_src.s_addr; + if (NULL == buffer || NULL == data || 0 == data_len) + { + return -1; + } + buffer->buffer = REALLOC(char, buffer->buffer, buffer->buffer_size + data_len); + memcpy(buffer->buffer + buffer->buffer_size, data, data_len); + buffer->buffer_size += data_len; + return 0; } -} -static void httpd_set_ipv6_addr(const struct ip6_hdr *ip6h, struct httpd_session_addr *addr, enum flow_type fdir) -{ - addr->ipver = 6; - if (FLOW_TYPE_C2S == fdir) + + int http_buffer_read(struct http_buffer *buffer, char **data, size_t *data_len) { - memcpy(&addr->saddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); - memcpy(&addr->daddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); + if (NULL == buffer) + { + if (data) + { + *data = NULL; + } + if (data_len) + { + *data_len = 0; + } + return -1; + } + *data = buffer->buffer; + *data_len = buffer->buffer_size; + return 0; } - else + + char *http_string_dup(const char *str, size_t len) { - memcpy(&addr->saddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); - memcpy(&addr->daddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); + if (NULL == str || 0 == len) + { + return NULL; + } + char *new_str = ALLOC(char, len); + memcpy(new_str, str, len); + return new_str; } -} -void httpd_session_get_addr(const struct session *sess, struct httpd_session_addr *addr) -{ - if (sess == NULL || addr == NULL) + long long http_strtoll(const char *str, size_t strlen) { - return; + if (NULL == str || 0 == strlen || strlen >= 19 /* INT64_MAX */) + { + return 0; + } + char tmp_str[strlen + 1]; + memcpy(tmp_str, str, strlen); + tmp_str[strlen] = '\0'; + return strtoll(tmp_str, NULL, 10); } - enum flow_type fdir = session_get_flow_type(sess); - const struct packet *raw_pkt = session_get_first_packet(sess, fdir); - if (NULL == raw_pkt) + + /* + * return value: + * EOF offset of beggining. + */ + size_t http_line_header_completed(const char *data, size_t data_len) { - addr->ipver = 0; - return; + if (data_len < 4) //"\r\n\r\n" + { + return 0; + } + void *ptr = memmem(data, data_len, "\r\n\r\n", 4); + if (ptr != NULL) + { + return (char *)ptr - data + 4; + } + return 0; } - int count = packet_get_layer_count(raw_pkt); - for (int i = count - 1; i >= 0; i--) + int http_protocol_identify(const char *data, size_t data_len) { - const struct layer *layer = packet_get_layer_by_idx(raw_pkt, i); - if (layer->proto == LAYER_PROTO_TCP) + llhttp_t parser; + llhttp_settings_t settings; + enum llhttp_errno error; + + if (NULL == data || 0 == data_len) { - httpd_set_tcp_addr(layer->hdr.tcp, addr, fdir); + return -1; } - else if (layer->proto == LAYER_PROTO_IPV4) + llhttp_settings_init(&settings); + llhttp_init(&parser, HTTP_BOTH, &settings); + + data_len = MIN(HTTP_IDENTIFY_LEN, data_len); + error = llhttp_execute(&parser, data, data_len); + if (error != HPE_OK) { - httpd_set_ipv4_addr(layer->hdr.ip4, addr, fdir); - break; + return -1; } - else if (layer->proto == LAYER_PROTO_IPV6) + return 1; + } + + void http_truncate_extract_headers(const char *raw_data, size_t raw_data_len, const char **headers_start, const char **headers_end) + { + const char *start = memmem(raw_data, raw_data_len, "\r\n", 2); + if (start != NULL) { - httpd_set_ipv6_addr(layer->hdr.ip6, addr, fdir); - break; + start += 2; + *headers_start = start; } + else + { + *headers_start = NULL; + } + const char *end = memmem(raw_data, raw_data_len, "\r\n\r\n", 4); + if (end != NULL) + { + end += 4; + *headers_end = end; + } + else + { + *headers_start = NULL; + *headers_end = NULL; + } + return; } -}
\ No newline at end of file + +#ifdef __cplusplus +} +#endif
\ No newline at end of file |
