📄 hi_client.c
字号:
** ** If there is a function, we call that function and process. It's ** important to note that the function that is called is responsible ** for incrementing the ptr to the next char to be inspected. The ** loop does not increment the pointer when a function is called to ** allow the maximum flexibility to the functions. */ while(hi_util_in_bounds(start, end, ptr)) { /* isascii returns non-zero if it is ascii */ if (isascii((int)*ptr) == 0) { /* Possible post data or something else strange... */ iRet = URI_END; break; } if(lookup_table[*ptr] || ServerConf->whitespace[*ptr]) { if(lookup_table[*ptr]) { iRet = (lookup_table[*ptr])(Session, start, end, &ptr, uri_ptr); } else { iRet = NextNonWhiteSpace(Session, start, end, &ptr, uri_ptr); } if(iRet) { if(iRet == URI_END) { /* ** You found a URI, let's break and check it out. */ break; } else if(iRet == HI_OUT_OF_BOUNDS) { /* ** Means you've reached the end of the buffer. THIS ** DOESN'T MEAN YOU HAVEN'T FOUND A URI. */ break; } else /* NO_URI */ { /* ** Check for chunk encoding, because the delimiter can ** also be a space, which would look like a pipeline request ** to us if we don't do this first. */ if(Session->server_conf->chunk_length) CheckChunkEncoding(Session, start, end); /* ** We only inspect the packet for another pipeline ** request if there wasn't a previous pipeline request. ** The reason that we do this is because */ if(!Client->request.pipeline_req) { /* ** Just because there was no URI in the first part ** the packet, doesn't mean that this isn't a ** pipelined request that has been segmented. */ if(!ServerConf->no_pipeline) { Client->request.pipeline_req = FindPipelineReq(Session, ptr, end); if(Client->request.pipeline_req) { return HI_SUCCESS; } } } return HI_NONFATAL_ERR; } } else { /* ** This means that we found the next non-whitespace char ** and since we are already pointed there, so we just ** continue. */ continue; } } ptr++; } return iRet;}/*** NAME** hi_client_extract_header::*//**** Catch multiple requests per packet, by returning pointer to after the** end of the request header if there is another request.** ** There are 4 types of "valid" delimiters that we look for. They are:** "\r\n\r\n"** "\r\n\n"** "\n\r\n"** "\n\n"** The only patterns that we really only need to look for are:** "\n\r\n"** "\n\n"** The reason being that these two patterns are suffixes of the other ** patterns. So once we find those, we are all good.** ** @param Session pointer to the session** @param start pointer to the start of text** @param end pointer to the end of text** ** @return pointer** ** @retval NULL Did not find pipeline request** @retval !NULL Found another possible request.*/static INLINE const u_char *hi_client_extract_header( HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, HI_CLIENT * Client, HEADER_PTR *header_ptr, const u_char *start, const u_char *end){ int iRet = HI_SUCCESS; const u_char *p; const u_char *offset; URI_PTR version_string; COOKIE_PTR *cookie_ptr = NULL; if(!start || !end) return NULL; p = start; /* ** We say end - 6 because we need at least six bytes to verify that ** there is an end to the URI and still a request afterwards. To be ** exact, we should only subtract 1, but we are not interested in a ** 1 byte method, uri, etc. ** ** a.k.a there needs to be data after the initial request to inspect ** to make it worth our while. */ if (p > (end - 6 )) { header_ptr->header.uri = NULL; return p; } /* This is to skip past the HTTP/1.0 (or 1.1) version string */ if (IsHttpVersion(&p, end)) { memset(&version_string, 0, sizeof(URI_PTR)); version_string.uri = p; while (hi_util_in_bounds(start, end, p)) { if(lookup_table[*p] || ServerConf->whitespace[*p]) { if(lookup_table[*p]) { iRet = (lookup_table[*p])(Session, start, end, &p, &version_string); } else { iRet = NextNonWhiteSpace(Session, start, end, &p, &version_string); } if(iRet == URI_END) { if (*p == '\n') { p++; if (hi_util_in_bounds(start, end, p)) { version_string.uri_end = p; } else { return p; } } break; } else if(iRet == HI_OUT_OF_BOUNDS) { return p; } } p++; } if (iRet == URI_END) { header_ptr->header.uri = version_string.uri_end + 1; offset = (u_char *)p; } else { return p; } } offset = (u_char*)p; header_ptr->header.uri = p; while (hi_util_in_bounds(start, end, p)) { if(*p == '\n') { if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len) && ((p - offset) >= Session->server_conf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } p++; offset = (u_char*)p; if (!hi_util_in_bounds(start, end, p)) { header_ptr->header.uri_end = p; return p; } /* As performance ugly as this may be, need to bounds check p in each of the * if blocks below to prevent read beyond end of buffer */ if (*p < 0x0E) { if(*p == '\r') { p++; if(hi_util_in_bounds(start, end, p) && (*p == '\n')) { header_ptr->header.uri_end = p; return ++p; } } else if(*p == '\n') { header_ptr->header.uri_end = p; return ++p; } } else if (((p - offset) == 0) && ((*p == 'C') || (*p == 'c'))) { /* Search for 'Cookie' at beginning, starting from current *p */ if (hi_util_in_bounds(start, end, p+6)) { if (!strncasecmp((const char *)p, "Cookie", 6)) { if (header_ptr->cookie.cookie) { /* unusal, multiple cookies... alloc new cookie pointer */ COOKIE_PTR *extra_cookie = calloc(1, sizeof(COOKIE_PTR)); if (!extra_cookie) { /* Failure to allocate, stop where we are... */ header_ptr->header.uri_end = p; return p; } cookie_ptr->next = extra_cookie; cookie_ptr = extra_cookie; /* extra_cookie->next = NULL; */ /* removed, since calloc NULLs this. */ } else { cookie_ptr = &header_ptr->cookie; } cookie_ptr->cookie = p; { const u_char *crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\r\n"); //const u_char *crlf = (const u_char *)strstr((const char *)p, "\r\n"); /* find a \r\n (CRLF) */ if (crlf) /* && hi_util_in_bounds(start, end, crlf+1)) bounds is checked in SnortStrnStr */ { cookie_ptr->cookie_end = crlf + 2; p = crlf; } else { header_ptr->header.uri_end = cookie_ptr->cookie_end = end; return end; } } } } } } p++; } /* Never observed an end-of-field. Maybe it's not there, but the header is long anyway: */ if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len) && ((p - start) >= Session->server_conf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } header_ptr->header.uri_end = p; return p;}#define CLR_POST(Client) \ do { \ Client->request.post_raw = NULL;\ Client->request.post_raw_size = 0;\ Client->request.post_norm = NULL; \ } while(0);#define CLR_HEADER(Client) \ do { \ Client->request.header_raw = NULL;\ Client->request.header_raw_size = 0;\ Client->request.header_norm = NULL; \ Client->request.cookie.cookie = NULL;\ Client->request.cookie.cookie_end = NULL;\ Client->request.cookie.next = NULL;\ } while(0);/*** NAME** StatelessInspection::*//**** Find the URI and determine whether the URI needs to be normalized.** ** This is a big step in stateless inspection, because we need to reliably** find the URI and when possible filter out non-URIs. We do this using a** simple state machine that is based on characters found in the data** buffer.** ** Another important aspect of the stateless inspection is the ability to** track and inspect pipelined requests. It is VERY IMPORTANT to reset the** pipeline_req pointer, since we don't memset the whole structure. This** pointer is reset in the hi_si_session_inspection() function. Check there** for more details.** ** Normalization is detected when we are looking at the packet for the URI.** We look for the following issues:** - ////** - /../** - /./** - non-ascii charss** - %** - \** When these things are seen we point to the first occurence in the URI, or** where we have to start normalizing. If the URI is updated to a new** pointer, then the normalization pointer is reset and we start over.** Using this method should cut down the memcpy()s per URI, since most** URIs are not normalized.** ** If this function returns HI_NONFATAL_ERR, we return out of mode_inspection** with an error and abort HttpInspect processing, and continue on with** any other processing we do. The Session parameters that we use here are** reset in the next time that we do session_inspection, so we don't do** any initialization here.** ** @param Session pointer to the HTTP session** @param data pointer to the start of the packet payload** @param dsize size of the payload** ** @return integer** ** @retval HI_INVALID_ARG invalid argument** @retval HI_NONFATAL_ERR no URI detected** @retval HI_SUCCESS URI detected and Session pointers updated*/static int StatelessInspection(HI_SESSION *Session, const unsigned char *data, int dsize){ HTTPINSPECT_CONF *ServerConf; HTTPINSPECT_CONF *ClientConf; HI_CLIENT *Client; URI_PTR method_ptr; URI_PTR uri_ptr; URI_PTR post_ptr; HEADER_PTR header_ptr; const u_char *start; const u_char *end; const u_char *ptr, *mthd; const u_char *method_end = NULL; int method_len; int iRet; int len; char non_ascii_mthd = 0; char sans_uri = 0; if(!Session || !data || dsize < 1) { return HI_INVALID_ARG; } ServerConf = Session->server_conf; if(!ServerConf) { return HI_INVALID_ARG; } ClientConf = Session->client_conf; if(!ClientConf) { return HI_INVALID_ARG; } Client = &Session->client; memset(&uri_ptr, 0x00, sizeof(URI_PTR)); memset(&post_ptr, 0x00, sizeof(URI_PTR)); memset(&header_ptr, 0x00, sizeof(HEADER_PTR)); memset(&method_ptr, 0x00, sizeof(URI_PTR)); /* ** We set the starting boundary depending on whether this request is ** a normal request or a pipeline request. The end boundary is always ** the same whether it is a pipeline request or other. */ if(Client->request.pipeline_req) { start = Client->request.pipeline_req; } else { start = data; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -