summaryrefslogtreecommitdiff
path: root/decoders/http/http_decoder_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'decoders/http/http_decoder_utils.c')
-rw-r--r--decoders/http/http_decoder_utils.c536
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