#include #include #include #include "stellar/http.h" #include "stellar/utils.h" #include "http_decoder_utils.h" #include "http_decoder.h" #include "llhttp.h" #ifdef __cplusplus extern "C" { #endif char *http_safe_dup(const char *str, size_t len) { if (str == NULL || len == 0) { return NULL; } char *dup = CALLOC(char, len + 1); memcpy(dup, str, len); return dup; } 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) { return -1; } if (fix_n1 != dyn_n2) { return -1; } return strncasecmp(fix_s1, dyn_s2, fix_n1); } const char *http_topic_type_to_string(enum http_topic_type type) { const char *sname = "unknown_topic"; 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; } 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 // 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) { return 0; } size_t alloc = length; while (alloc) { 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; } int httpd_url_is_encoded(const char *url, size_t len) { for (size_t i = 0; i < len; i++) { if (url[i] == '%') { return 1; } } return 0; } static void httpd_set_tcp_addr(const struct tcphdr *tcph, struct http_session_addr *addr, enum flow_type fdir) { 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; } } static void httpd_set_ipv4_addr(const struct ip *ip4h, struct http_session_addr *addr, enum flow_type fdir) { 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; } } static void httpd_set_ipv6_addr(const struct ip6_hdr *ip6h, struct http_session_addr *addr, enum flow_type fdir) { addr->ipver = 6; if (FLOW_TYPE_C2S == fdir) { memcpy(&addr->saddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); memcpy(&addr->daddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); } else { memcpy(&addr->saddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); memcpy(&addr->daddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); } } void httpd_session_get_addr(const struct session *sess, struct http_session_addr *addr) { 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) { 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; } } } void http_session_addr_ntop(const struct http_session_addr *sesaddr, char *buf, size_t buflen) { 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); } struct http_buffer *http_buffer_new(void) { struct http_buffer *buffer = CALLOC(struct http_buffer, 1); buffer->buffer = NULL; buffer->buffer_size = 0; buffer->reference = 1; return buffer; } void http_buffer_free(struct http_buffer *buffer) { if (NULL == buffer) { return; } if (buffer->reference > 1) { buffer->reference--; return; } if (buffer->buffer) { FREE(buffer->buffer); } FREE(buffer); } int http_buffer_add(struct http_buffer *buffer, const char *data, size_t data_len) { 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; } int http_buffer_read(struct http_buffer *buffer, char **data, size_t *data_len) { 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; } char *http_string_dup(const char *str, size_t len) { if (NULL == str || 0 == len) { return NULL; } char *new_str = ALLOC(char, len); memcpy(new_str, str, len); return new_str; } long long http_strtoll(const char *str, size_t strlen) { 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); } /* * return value: * EOF offset of beggining. */ size_t http_line_header_completed(const char *data, size_t data_len) { 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 http_protocol_identify(const char *data, size_t data_len) { llhttp_t parser; llhttp_settings_t settings; enum llhttp_errno error; if (NULL == data || 0 == data_len) { return -1; } 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) { return -1; } 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) { 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; } #ifdef __cplusplus } #endif