00001 /** 00002 ** @file hi_client.c 00003 ** 00004 ** @author Daniel Roelker <droelker@sourcefire.com> 00005 ** 00006 ** @brief Main file for all the client functions and inspection 00007 ** flow. 00008 ** 00009 ** Copyright (C) 2003-2005 Sourcefire,Inc. 00010 ** 00011 ** The job of the client module is to analyze and inspect the HTTP 00012 ** protocol, finding where the various fields begin and end. This must 00013 ** be accomplished in a stateful and stateless manner. 00014 ** 00015 ** While the fields are being determined, we also do checks for 00016 ** normalization, so we don't normalize fields that don't need it. 00017 ** 00018 ** Currently, the only fields we check for this is the URI and the 00019 ** parameter fields. 00020 ** 00021 ** NOTES: 00022 ** - 3.8.03: Initial development. DJR 00023 ** - 2.4.05: Added tab_uri_delimiter config option. AJM. 00024 */ 00025 00026 #include <stdlib.h> 00027 #include <stdio.h> 00028 #include <string.h> 00029 #include <ctype.h> 00030 #include <sys/types.h> 00031 00032 #include "hi_ui_config.h" 00033 #include "hi_si.h" 00034 #include "hi_mi.h" 00035 #include "hi_client.h" 00036 #include "hi_eo_log.h" 00037 #include "hi_util.h" 00038 #include "hi_util_hbm.h" 00039 #include "hi_return_codes.h" 00040 00041 #define URI_END 1 00042 #define NO_URI -1 00043 #define INVALID_HEX_VAL -1 00044 00045 /** 00046 ** This structure holds pointers to the different sections of an HTTP 00047 ** request. We need to track where whitespace begins and ends, so we 00048 ** can evaluate the placement of the URI correctly. 00049 ** 00050 ** For example, 00051 ** 00052 ** GET / HTTP/1.0 00053 ** ^ ^ 00054 ** start end 00055 ** 00056 ** The end space pointers are set to NULL if there is space until the end 00057 ** of the buffer. 00058 */ 00059 typedef struct s_URI_PTR 00060 { 00061 u_char *uri; /* the beginning of the URI */ 00062 u_char *uri_end; /* the end of the URI */ 00063 u_char *norm; /* ptr to first normalization occurence */ 00064 u_char *ident; /* ptr to beginning of the HTTP identifier */ 00065 u_char *first_sp_start; /* beginning of first space delimiter */ 00066 u_char *first_sp_end; /* end of first space delimiter */ 00067 u_char *second_sp_start; /* beginning of second space delimiter */ 00068 u_char *second_sp_end; /* end of second space delimiter */ 00069 u_char *param; /* '?' (beginning of parameter field) */ 00070 u_char *delimiter; /* HTTP URI delimiter (\r\n\) */ 00071 u_char *last_dir; /* ptr to last dir, so we catch long dirs */ 00072 u_char *proxy; /* ptr to the absolute URI */ 00073 } URI_PTR; 00074 00075 /** 00076 ** This makes passing function arguments much more readable and easier 00077 ** to follow. 00078 */ 00079 typedef int (*LOOKUP_FCN)(HI_SESSION *, u_char *, u_char *, u_char **, 00080 URI_PTR *); 00081 00082 /* 00083 ** The lookup table contains functions for different HTTP delimiters 00084 ** (like whitespace and the HTTP delimiter \r and \n). 00085 */ 00086 static LOOKUP_FCN lookup_table[256]; 00087 static int hex_lookup[256]; 00088 00089 /* 00090 ** NAME 00091 ** CheckChunkEncoding:: 00092 */ 00093 /** 00094 ** This routine checks for chunk encoding anomalies in an HTTP client request 00095 ** packet. 00096 ** 00097 ** We convert potential chunk lengths and test them against the user-defined 00098 ** max chunk length. We log events on any chunk lengths that are over this 00099 ** defined chunk lengths. 00100 ** 00101 ** Chunks are skipped to save time when the chunk is contained in the packet. 00102 ** 00103 ** We assume coming into this function that we are pointed at the beginning 00104 ** of what may be a chunk length. That's why the iCheckChunk var is set 00105 ** to 1. 00106 ** 00107 ** @param Session pointer to the Session construct 00108 ** @param start pointer to where to beginning of buffer 00109 ** @param end pointer to the end of buffer 00110 ** 00111 ** @return integer 00112 ** 00113 ** @retval HI_SUCCESS function successful 00114 ** @retval HI_INVALID_ARG invalid argument 00115 */ 00116 static int CheckChunkEncoding(HI_SESSION *Session, u_char *start, u_char *end) 00117 { 00118 int iChunkLen = 0; 00119 int iChunkChars = 0; 00120 int iCheckChunk = 1; 00121 u_char *ptr; 00122 u_char *jump_ptr; 00123 00124 if(!start || !end) 00125 return HI_INVALID_ARG; 00126 00127 ptr = start; 00128 00129 while(hi_util_in_bounds(start, end, ptr)) 00130 { 00131 if(*ptr == '\n' || *ptr == ' ' || *ptr == '\t') 00132 { 00133 if(iCheckChunk && iChunkLen != 0) 00134 { 00135 if(Session->server_conf->chunk_length < iChunkLen && 00136 hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK)) 00137 { 00138 hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK, 00139 NULL, NULL); 00140 } 00141 00142 jump_ptr = ptr + iChunkLen; 00143 00144 if(jump_ptr <= ptr) 00145 { 00146 break; 00147 } 00148 00149 if(hi_util_in_bounds(start, end, jump_ptr)) 00150 { 00151 ptr = jump_ptr; 00152 } 00153 else 00154 { 00155 /* 00156 ** Chunk too large for packet, so we bail 00157 */ 00158 break; 00159 } 00160 } 00161 00162 /* 00163 ** If we've already evaluated the chunk, or we have a valid delimiter 00164 ** for handling new chunks, we reset and starting evaluating possible 00165 ** chunk lengths. 00166 */ 00167 if(iCheckChunk || *ptr == '\n') 00168 { 00169 iCheckChunk = 1; 00170 iChunkLen = 0; 00171 iChunkChars = 0; 00172 } 00173 00174 ptr++; 00175 continue; 00176 } 00177 00178 if(iCheckChunk) 00179 { 00180 if(hex_lookup[*ptr] == INVALID_HEX_VAL) 00181 { 00182 if(*ptr == '\r') 00183 { 00184 ptr++; 00185 00186 if(!hi_util_in_bounds(start, end, ptr)) 00187 break; 00188 00189 if(*ptr == '\n') 00190 continue; 00191 } 00192 else if(*ptr == ';') 00193 { 00194 /* 00195 ** This is where we skip through the chunk name=value 00196 ** field. 00197 */ 00198 ptr++; 00199 00200 while(hi_util_in_bounds(start, end, ptr)) 00201 { 00202 if(*ptr == '\n') 00203 break; 00204 00205 ptr++; 00206 } 00207 00208 continue; 00209 } 00210 00211 iCheckChunk = 0; 00212 iChunkLen = 0; 00213 iChunkChars = 0; 00214 } 00215 else 00216 { 00217 if(iChunkChars >= 8) 00218 { 00219 iCheckChunk = 0; 00220 iChunkLen = 0; 00221 iChunkChars = 0; 00222 } 00223 else 00224 { 00225 iChunkLen <<= 4; 00226 iChunkLen |= (unsigned int)hex_lookup[*ptr]; 00227 00228 iChunkChars++; 00229 } 00230 } 00231 } 00232 00233 ptr++; 00234 } 00235 00236 return HI_SUCCESS; 00237 } 00238 00239 /* 00240 ** NAME 00241 ** FindPipelineReq:: 00242 */ 00243 /** 00244 ** Catch multiple requests per packet, by returning pointer to after the 00245 ** end of the request header if there is another request. 00246 ** 00247 ** There are 4 types of "valid" delimiters that we look for. They are: 00248 ** "\r\n\r\n" 00249 ** "\r\n\n" 00250 ** "\n\r\n" 00251 ** "\n\n" 00252 ** The only patterns that we really only need to look for are: 00253 ** "\n\r\n" 00254 ** "\n\n" 00255 ** The reason being that these two patterns are suffixes of the other 00256 ** patterns. So once we find those, we are all good. 00257 ** 00258 ** @param start pointer to the start of text 00259 ** @param end pointer to the end of text 00260 ** 00261 ** @return pointer 00262 ** 00263 ** @retval NULL Did not find pipeline request 00264 ** @retval !NULL Found another possible request. 00265 */ 00266 static INLINE u_char *FindPipelineReq(u_char *start, u_char *end) 00267 { 00268 u_char *p; 00269 00270 if(!start || !end) 00271 return NULL; 00272 00273 p = start; 00274 00275 /* 00276 ** We say end - 6 because we need at least six bytes to verify that 00277 ** there is an end to the URI and still a request afterwards. To be 00278 ** exact, we should only subtract 1, but we are not interested in a 00279 ** 1 byte method, uri, etc. 00280 ** 00281 ** a.k.a there needs to be data after the initial request to inspect 00282 ** to make it worth our while. 00283 */ 00284 while(p < (end - 6)) 00285 { 00286 if(*p == '\n') 00287 { 00288 p++; 00289 00290 if(*p < 0x0E) 00291 { 00292 if(*p == '\r') 00293 { 00294 p++; 00295 00296 if(*p == '\n') 00297 { 00298 return ++p; 00299 } 00300 } 00301 else if(*p == '\n') 00302 { 00303 return ++p; 00304 } 00305 } 00306 } 00307 00308 p++; 00309 } 00310 00311 return NULL; 00312 } 00313 00314 /* 00315 ** NAME 00316 ** IsHttpVersion:: 00317 */ 00318 /** 00319 ** This checks that there is a version following a space with in an HTTP 00320 ** packet. 00321 ** 00322 ** This function gets called when a whitespace area has ended, and we want 00323 ** to know if a version identifier is followed directly after. So we look 00324 ** for the rfc standard "HTTP/" and report appropriately. We also need 00325 ** to make sure that the function succeeds given an end of buffer, so for 00326 ** instance if the buffer ends like " HTT", we still assume that this is 00327 ** a valid version identifier because of TCP segmentation. 00328 ** 00329 ** We also check for the 0.9 standard of GET URI\r\n. When we see a \r or 00330 ** a \n, then we just return with the pointer still pointing to that char. 00331 ** The reason is because on the next loop, we'll do the evaluation that 00332 ** we normally do and finish up processing there. 00333 ** 00334 ** @param start pointer to the start of the version identifier 00335 ** @param end pointer to the end of the buffer (could be the end of the 00336 ** data section, or just to the beginning of the delimiter. 00337 ** 00338 ** @return integer 00339 ** 00340 ** @retval 1 this is an HTTP version identifier 00341 ** @retval 0 this is not an HTTP identifier, or bad parameters 00342 */ 00343 static int IsHttpVersion(u_char **ptr, u_char *end) 00344 { 00345 static u_char s_acHttpDelimiter[] = "HTTP/"; 00346 static int s_iHttpDelimiterLen = 5; 00347 int len; 00348 int iCtr; 00349 00350 if(*ptr >= end) 00351 { 00352 return 0; 00353 } 00354 00355 len = end - *ptr; 00356 if(len > s_iHttpDelimiterLen) 00357 { 00358 len = s_iHttpDelimiterLen; 00359 } 00360 00361 /* 00362 ** This is where we check for the defunct method again. This method 00363 ** allows a request of "GET /index.html \r[\n]". So we need to 00364 ** check validate this as a legal identifier. 00365 */ 00366 if(**ptr == '\n' || **ptr == '\r') 00367 { 00368 /* 00369 ** We don't increment the pointer because we check for a legal 00370 ** identifier in the delimiter checking. Read the comments for 00371 ** setting the defunct variable in these functions. 00372 */ 00373 return 1; 00374 } 00375 00376 for(iCtr = 0; iCtr < len; iCtr++) 00377 { 00378 if(s_acHttpDelimiter[iCtr] != (u_char)toupper((int)**ptr)) 00379 { 00380 return 0; 00381 } 00382 00383 (*ptr)++; 00384 } 00385 00386 /* 00387 ** This means that we match all the chars that we could given the 00388 ** remaining length so we should increment the pointer by that much 00389 ** since we don't need to inspect this again. 00390 */ 00391 (*ptr)++; 00392 00393 return 1; 00394 } 00395 00396 /* 00397 ** NAME 00398 ** find_rfc_delimiter:: 00399 */ 00400 /** 00401 ** Check for standard RFC HTTP delimiter. 00402 ** 00403 ** If we find the delimiter, we return that URI_PTR structures should 00404 ** be checked, which bails us out of the loop. If there isn't a RFC 00405 ** delimiter, then we bail with a no URI. Otherwise, we check for out 00406 ** of bounds. 00407 ** 00408 ** @param ServerConf pointer to the server configuration 00409 ** @param start pointer to the start of payload 00410 ** @param end pointer to the end of the payload 00411 ** @param ptr pointer to the pointer of the current index 00412 ** @param uri_ptr pointer to the URI_PTR construct 00413 ** 00414 ** @return integer 00415 ** 00416 ** @retval HI_OUT_OF_BOUNDS 00417 ** @retval URI_END end of the URI is found, check URI_PTR. 00418 ** @retval NO_URI malformed delimiter, no URI. 00419 */ 00420 static int find_rfc_delimiter(HI_SESSION *Session, u_char *start, 00421 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 00422 { 00423 if(*ptr == start || !uri_ptr->uri) 00424 return NO_URI; 00425 00426 /* 00427 ** This is important to catch the defunct way of getting URIs without 00428 ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for 00429 ** us to tell if we are in that state. 00430 ** 00431 ** We check for a legal identifier to deal with the case of 00432 ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. 00433 ** Since we find a "valid" (still defunct) delimiter, we account for 00434 ** it here, so that we don't set the uri_end to the delimiter. 00435 ** 00436 ** NOTE: 00437 ** We now assume that the defunct method is in effect and if there is 00438 ** a valid identifier, then we don't update the uri_end because it's 00439 ** already been set when the identifier was validated. 00440 */ 00441 00442 (*ptr)++; 00443 if(!hi_util_in_bounds(start, end, *ptr)) 00444 { 00445 return HI_OUT_OF_BOUNDS; 00446 } 00447 00448 if(**ptr == '\n') 00449 { 00450 uri_ptr->delimiter = (*ptr)-1; 00451 00452 if(!uri_ptr->ident) 00453 uri_ptr->uri_end = uri_ptr->delimiter; 00454 00455 return URI_END; 00456 } 00457 00458 return NO_URI; 00459 } 00460 00461 /* 00462 ** NAME 00463 ** find_non_rfc_delimiter:: 00464 */ 00465 /** 00466 ** Check for non standard delimiter '\n'. 00467 ** 00468 ** It now appears that apache and iis both take this non-standard 00469 ** delimiter. So, we most likely will always look for it, but maybe 00470 ** give off a special alert or something. 00471 ** 00472 ** @param ServerConf pointer to the server configuration 00473 ** @param start pointer to the start of payload 00474 ** @param end pointer to the end of the payload 00475 ** @param ptr pointer to the pointer of the current index 00476 ** @param uri_ptr pointer to the URI_PTR construct 00477 ** 00478 ** @return integer 00479 ** 00480 ** @retval URI_END delimiter found, end of URI 00481 ** @retval NO_URI 00482 */ 00483 static int find_non_rfc_delimiter(HI_SESSION *Session, u_char *start, 00484 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 00485 { 00486 HTTPINSPECT_CONF *ServerConf = Session->server_conf; 00487 00488 if(*ptr == start || !uri_ptr->uri) 00489 return NO_URI; 00490 00491 /* 00492 ** This is important to catch the defunct way of getting URIs without 00493 ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for 00494 ** us to tell if we are in that state. 00495 ** 00496 ** We check for a legal identifier to deal with the case of 00497 ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. 00498 ** Since we find a "valid" (still defunct) delimiter, we account for 00499 ** it here, so that we don't set the uri_end to the delimiter. 00500 ** 00501 ** NOTE: 00502 ** We now assume that the defunct method is in effect and if there is 00503 ** a valid identifier, then we don't update the uri_end because it's 00504 ** already been set when the identifier was validated. 00505 */ 00506 if(ServerConf->iis_delimiter.on) 00507 { 00508 if(hi_eo_generate_event(Session, ServerConf->iis_delimiter.alert)) 00509 { 00510 hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_DELIMITER, 00511 NULL, NULL); 00512 } 00513 00514 uri_ptr->delimiter = *ptr; 00515 00516 if(!uri_ptr->ident) 00517 uri_ptr->uri_end = uri_ptr->delimiter; 00518 00519 return URI_END; 00520 } 00521 00522 /* 00523 ** This allows us to do something if the delimiter check is not turned 00524 ** on. Most likely this is worthy of an alert, IF it's not normal to 00525 ** see these requests. 00526 ** 00527 ** But for now, we always return true. 00528 */ 00529 uri_ptr->delimiter = *ptr; 00530 00531 if(!uri_ptr->ident) 00532 uri_ptr->uri_end = uri_ptr->delimiter; 00533 00534 return URI_END; 00535 } 00536 00537 /* 00538 ** NAME 00539 ** NextNonWhiteSpace:: 00540 */ 00541 /** 00542 ** Update the URI_PTR fields spaces, find the next non-white space char, 00543 ** and validate the HTTP version identifier after the spaces. 00544 ** 00545 ** This is the main part of the URI algorithm. This verifies that there 00546 ** isn't too many spaces in the data to be a URI, it checks that after the 00547 ** second space that there is an HTTP identifier or otherwise it's no good. 00548 ** Also, if we've found an identifier after the first whitespace, and 00549 ** find another whitespace, there is no URI. 00550 ** 00551 ** The uri and uri_end pointers are updated in this function depending 00552 ** on what space we are at, and if the space was followed by the HTTP 00553 ** identifier. (NOTE: the HTTP delimiter is no longer "HTTP/", but 00554 ** can also be "\r\n", "\n", or "\r". This is the defunct method, and 00555 ** we deal with it in the IsHttpVersion and delimiter functions.) 00556 ** 00557 ** @param ServerConf pointer to the server configuration 00558 ** @param start pointer to the start of payload 00559 ** @param end pointer to the end of the payload 00560 ** @param ptr pointer to the pointer of the current index 00561 ** @param uri_ptr pointer to the URI_PTR construct 00562 ** 00563 ** @return integer 00564 ** 00565 ** @retval HI_SUCCESS found the next non-whitespace 00566 ** @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer 00567 ** @retval URI_END delimiter found, end of URI 00568 ** @retval NO_URI 00569 */ 00570 static int NextNonWhiteSpace(HI_SESSION *Session, u_char *start, 00571 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 00572 { 00573 HTTPINSPECT_CONF *ServerConf = Session->server_conf; 00574 u_char **start_sp; 00575 u_char **end_sp; 00576 00577 /* 00578 ** Horizontal tab is only accepted by apache web servers, not IIS. 00579 ** Some IIS exploits contain a tab (0x09) in the URI, so we don't want 00580 ** to treat it as a URI delimiter and cut off the URI. 00581 */ 00582 if ( **ptr == '\t' && !ServerConf->tab_uri_delimiter ) 00583 { 00584 (*ptr)++; 00585 return HI_SUCCESS; 00586 } 00587 00588 /* 00589 ** Reset the identifier, because we've just seen another space. We 00590 ** should only see the identifier immediately after a space followed 00591 ** by a delimiter. 00592 */ 00593 if(uri_ptr->ident) 00594 { 00595 if(ServerConf->non_strict) 00596 { 00597 /* 00598 ** In non-strict mode it is ok to see spaces after the 00599 ** "identifier", so we just increment the ptr and return. 00600 */ 00601 (*ptr)++; 00602 return HI_SUCCESS; 00603 } 00604 else 00605 { 00606 /* 00607 ** This means that we've already seen a space and a version 00608 ** identifier, and now that we've seen another space, we know 00609 ** that this can't be the URI so we just bail out with no 00610 ** URI. 00611 */ 00612 return NO_URI; 00613 } 00614 } 00615 00616 uri_ptr->ident = NULL; 00617 00618 /* 00619 ** We only check for one here, because both should be set if one 00620 ** is. 00621 */ 00622 if(uri_ptr->first_sp_end) 00623 { 00624 /* 00625 ** If the second space has been set, then this means that we have 00626 ** seen a third space, which we shouldn't see in the URI so we 00627 ** are now done and know there is no URI in this packet. 00628 */ 00629 if(uri_ptr->second_sp_end) 00630 { 00631 return NO_URI; 00632 } 00633 00634 /* 00635 ** Since we've seen the second space, we need to update the uri ptr 00636 ** to the end of the first space, since the URI cannot be before the 00637 ** first space. 00638 */ 00639 uri_ptr->uri = uri_ptr->first_sp_end; 00640 00641 uri_ptr->second_sp_start = *ptr; 00642 uri_ptr->second_sp_end = NULL; 00643 00644 start_sp = &uri_ptr->second_sp_start; 00645 end_sp = &uri_ptr->second_sp_end; 00646 } 00647 else 00648 { 00649 /* 00650 ** This means that there is whitespace at the beginning of the line 00651 ** and we unset the URI so we can set it later if need be. 00652 ** 00653 ** This is mainly so we handle data that is all spaces correctly. 00654 ** 00655 ** In the normal case where we've seen text and then the first space, 00656 ** we leave the uri ptr pointing at the beginning of the data, and 00657 ** set the uri end after we've determined where to put it. 00658 */ 00659 if(start == *ptr) 00660 uri_ptr->uri = NULL; 00661 00662 00663 uri_ptr->first_sp_start = *ptr; 00664 uri_ptr->first_sp_end = NULL; 00665 00666 start_sp = &uri_ptr->first_sp_start; 00667 end_sp = &uri_ptr->first_sp_end; 00668 } 00669 00670 while(hi_util_in_bounds(start, end, *ptr)) 00671 { 00672 /* 00673 ** Check for whitespace 00674 */ 00675 if(**ptr == ' ') 00676 { 00677 (*ptr)++; 00678 continue; 00679 } 00680 else if((**ptr == '\t')) 00681 { 00682 if(ServerConf->apache_whitespace.on) 00683 { 00684 if(hi_eo_generate_event(Session, 00685 ServerConf->apache_whitespace.alert)) 00686 { 00687 hi_eo_client_event_log(Session, HI_EO_CLIENT_APACHE_WS, 00688 NULL, NULL); 00689 } 00690 00691 (*ptr)++; 00692 continue; 00693 } 00694 else 00695 { 00696 return NO_URI; 00697 } 00698 } 00699 else 00700 { 00701 /* 00702 ** This sets the sp_end for whatever space delimiter we are on, 00703 ** whether that is the first space or the second space. 00704 */ 00705 *end_sp = *ptr; 00706 00707 if(!IsHttpVersion(ptr, end)) 00708 { 00709 /* 00710 ** This is the default method and what we've been doing 00711 ** since the start of development. 00712 */ 00713 if(uri_ptr->second_sp_start) 00714 { 00715 /* 00716 ** There is no HTTP version indentifier at the beginning 00717 ** of the second space, and this means that there is no 00718 ** URI. 00719 */ 00720 if(ServerConf->non_strict) 00721 { 00722 /* 00723 ** In non-strict mode, we must assume the URI is 00724 ** between the first and second space, so now 00725 ** that we've seen the second space that's the 00726 ** identifier. 00727 */ 00728 uri_ptr->ident = *end_sp; 00729 uri_ptr->uri_end = *start_sp; 00730 00731 return HI_SUCCESS; 00732 } 00733 else 00734 { 00735 /* 00736 ** Since we are in strict mode here, it means that 00737 ** we haven't seen a valid identifier, so there was 00738 ** no URI. 00739 */ 00740 return NO_URI; 00741 } 00742 } 00743 00744 /* 00745 ** RESET NECESSARY URI_PTRs HERE. This is the place where 00746 ** the uri is updated. It can only happen once, so do it 00747 ** right here. 00748 ** 00749 ** When we get here it means that we have found the end of 00750 ** the FIRST whitespace, and that there was no delimiter, 00751 ** so we reset the uri pointers and other related 00752 ** pointers. 00753 */ 00754 uri_ptr->uri = *end_sp; 00755 uri_ptr->uri_end = end; 00756 uri_ptr->norm = NULL; 00757 uri_ptr->last_dir = NULL; 00758 uri_ptr->param = NULL; 00759 uri_ptr->proxy = NULL; 00760 } 00761 else 00762 { 00763 /* 00764 ** Means we found the HTTP version identifier and we reset 00765 ** the uri_end pointer to point to the beginning of the 00766 ** whitespace detected. 00767 ** 00768 ** This works for both "uri_is_here HTTP/1.0" and 00769 ** "METHOD uri_is_here HTTP/1.0", so it works when the 00770 ** identifier is after either the first or the second 00771 ** whitespace. 00772 */ 00773 uri_ptr->ident = *end_sp; 00774 uri_ptr->uri_end = *start_sp; 00775 } 00776 00777 /* 00778 ** We found a non-whitespace char 00779 */ 00780 return HI_SUCCESS; 00781 } 00782 } 00783 00784 /* 00785 ** This is the case where we've seen text and found a whitespace until 00786 ** the end of the buffer. In that case, we set the uri_end to the 00787 ** beginning of the whitespace. 00788 */ 00789 uri_ptr->uri_end = *start_sp; 00790 00791 return HI_OUT_OF_BOUNDS; 00792 } 00793 00794 /* 00795 ** NAME 00796 ** SetPercentNorm:: 00797 */ 00798 /** 00799 ** Check for percent normalization in the URI buffer. 00800 ** 00801 ** We don't do much here besides check the configuration, set the pointer, 00802 ** and continue processing. 00803 ** 00804 ** @param ServerConf pointer to the server configuration 00805 ** @param start pointer to the start of payload 00806 ** @param end pointer to the end of the payload 00807 ** @param ptr pointer to the pointer of the current index 00808 ** @param uri_ptr pointer to the URI_PTR construct 00809 ** 00810 ** @return integer 00811 ** 00812 ** @retval HI_SUCCESS function successful 00813 */ 00814 static int SetPercentNorm(HI_SESSION *Session, u_char *start, 00815 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 00816 { 00817 HTTPINSPECT_CONF *ServerConf = Session->server_conf; 00818 00819 if(!uri_ptr->norm && !uri_ptr->ident) 00820 { 00821 if(ServerConf->ascii.on) 00822 { 00823 uri_ptr->norm = *ptr; 00824 } 00825 } 00826 00827 (*ptr)++; 00828 00829 return HI_SUCCESS; 00830 } 00831 00832 /* 00833 ** NAME 00834 ** CheckLongDir:: 00835 */ 00836 /** 00837 ** We check the directory length against the global config. 00838 ** 00839 ** @param Session pointer to the current session 00840 ** @param uri_ptr pointer to the URI state 00841 ** @param ptr pointer to the current index in buffer 00842 ** 00843 ** @return integer 00844 ** 00845 ** @retval HI_SUCCESS 00846 */ 00847 static INLINE int CheckLongDir(HI_SESSION *Session, URI_PTR *uri_ptr, 00848 u_char *ptr) 00849 { 00850 int iDirLen; 00851 00852 /* 00853 ** Check for oversize directory 00854 */ 00855 if(Session->server_conf->long_dir && uri_ptr->last_dir && 00856 !uri_ptr->param) 00857 { 00858 iDirLen = ptr - uri_ptr->last_dir; 00859 00860 if(iDirLen > Session->server_conf->long_dir && 00861 hi_eo_generate_event(Session, HI_EO_CLIENT_OVERSIZE_DIR)) 00862 { 00863 hi_eo_client_event_log(Session, HI_EO_CLIENT_OVERSIZE_DIR, 00864 NULL, NULL); 00865 } 00866 } 00867 00868 return HI_SUCCESS; 00869 00870 } 00871 00872 /* 00873 ** NAME 00874 ** SetSlashNorm:: 00875 */ 00876 /** 00877 ** Check for any directory traversal or multi-slash normalization. 00878 ** 00879 ** @param ServerConf pointer to the server configuration 00880 ** @param start pointer to the start of payload 00881 ** @param end pointer to the end of the payload 00882 ** @param ptr pointer to the pointer of the current index 00883 ** @param uri_ptr pointer to the URI_PTR construct 00884 ** 00885 ** @return integer 00886 ** 00887 ** @retval HI_SUCCESS function successful 00888 ** @retval HI_OUT_OF_BOUNDS reached the end of the buffer 00889 */ 00890 static int SetSlashNorm(HI_SESSION *Session, u_char *start, 00891 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 00892 { 00893 HTTPINSPECT_CONF *ServerConf = Session->server_conf; 00894 00895 CheckLongDir(Session, uri_ptr, *ptr); 00896 uri_ptr->last_dir = *ptr; 00897 00898 if(!uri_ptr->norm && !uri_ptr->ident) 00899 { 00900 00901 uri_ptr->norm = *ptr; 00902 00903 (*ptr)++; 00904 00905 if(!hi_util_in_bounds(start,end, *ptr)) 00906 { 00907 /* 00908 ** This is the case where there is a slash as the last char 00909 ** and we don't want to normalize that since there really 00910 ** is nothing to normalize. 00911 */ 00912 uri_ptr->norm = NULL; 00913 return HI_OUT_OF_BOUNDS; 00914 } 00915 00916 /* 00917 ** Check for directory traversals 00918 */ 00919 if(ServerConf->directory.on) 00920 { 00921 if(**ptr == '.') 00922 { 00923 (*ptr)++; 00924 if(!hi_util_in_bounds(start, end, *ptr)) 00925 { 00926 uri_ptr->norm = NULL; 00927 return HI_OUT_OF_BOUNDS; 00928 } 00929 00930 if(**ptr == '.' || ** ptr == '/') 00931 { 00932 return HI_SUCCESS; 00933 } 00934 } 00935 } 00936 00937 /* 00938 ** Check for multiple slash normalization 00939 */ 00940 if(ServerConf->multiple_slash.on) 00941 { 00942 if(**ptr == '/') 00943 { 00944 return HI_SUCCESS; 00945 } 00946 } 00947 00948 uri_ptr->norm = NULL; 00949 return HI_SUCCESS; 00950 } 00951 00952 (*ptr)++; 00953 00954 return HI_SUCCESS; 00955 } 00956 00957 /* 00958 ** NAME 00959 ** SetBackSlashNorm:: 00960 */ 00961 /** 00962 ** Check for backslashes and if we need to normalize. 00963 ** 00964 ** This really just checks the configuration option, and sets the norm 00965 ** variable if applicable. 00966 ** 00967 ** @param ServerConf pointer to the server configuration 00968 ** @param start pointer to the start of payload 00969 ** @param end pointer to the end of the payload 00970 ** @param ptr pointer to the pointer of the current index 00971 ** @param uri_ptr pointer to the URI_PTR construct 00972 ** 00973 ** @return integer 00974 ** 00975 ** @retval HI_SUCCESS function successful 00976 */ 00977 static int SetBackSlashNorm(HI_SESSION *Session, u_char *start, 00978 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 00979 { 00980 HTTPINSPECT_CONF *ServerConf = Session->server_conf; 00981 00982 if(!uri_ptr->norm && !uri_ptr->ident) 00983 { 00984 if(ServerConf->iis_backslash.on) 00985 { 00986 uri_ptr->norm = *ptr; 00987 } 00988 } 00989 00990 (*ptr)++; 00991 00992 return HI_SUCCESS; 00993 } 00994 00995 /* 00996 ** NAME 00997 ** SetBinaryNorm:: 00998 */ 00999 /** 01000 ** Look for non-ASCII chars in the URI. 01001 ** 01002 ** We look for these chars in the URI and set the normalization variable 01003 ** if it's not already set. I think we really only need this for IIS 01004 ** servers, but we may want to know if it's in the URI too. 01005 ** 01006 ** @param ServerConf pointer to the server configuration 01007 ** @param start pointer to the start of payload 01008 ** @param end pointer to the end of the payload 01009 ** @param ptr pointer to the pointer of the current index 01010 ** @param uri_ptr pointer to the URI_PTR construct 01011 ** 01012 ** @return integer 01013 ** 01014 ** @retval HI_SUCCESS function successful 01015 */ 01016 static int SetBinaryNorm(HI_SESSION *Session, u_char *start, 01017 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 01018 { 01019 if(!uri_ptr->norm && !uri_ptr->ident) 01020 { 01021 uri_ptr->norm = *ptr; 01022 } 01023 01024 (*ptr)++; 01025 01026 return HI_SUCCESS; 01027 } 01028 01029 /* 01030 ** NAME 01031 ** SetParamField:: 01032 */ 01033 /** 01034 ** This function sets the parameter field as the first '?'. The big thing 01035 ** is that we set the param value, so we don't false positive long dir 01036 ** events when it's really just a long parameter field. 01037 ** 01038 ** @param ServerConf pointer to the server configuration 01039 ** @param start pointer to the start of payload 01040 ** @param end pointer to the end of the payload 01041 ** @param ptr pointer to the pointer of the current index 01042 ** @param uri_ptr pointer to the URI_PTR construct 01043 ** 01044 ** @return integer 01045 ** 01046 ** @retval HI_SUCCESS function successful 01047 */ 01048 static int SetParamField(HI_SESSION *Session, u_char *start, 01049 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 01050 { 01051 if(!uri_ptr->ident) 01052 { 01053 uri_ptr->param = *ptr; 01054 } 01055 01056 (*ptr)++; 01057 01058 return HI_SUCCESS; 01059 } 01060 /* 01061 ** NAME 01062 ** SetProxy:: 01063 */ 01064 /** 01065 ** This function checks for an absolute URI in the URI. 01066 ** 01067 ** @param ServerConf pointer to the server configuration 01068 ** @param start pointer to the start of payload 01069 ** @param end pointer to the end of the payload 01070 ** @param ptr pointer to the pointer of the current index 01071 ** @param uri_ptr pointer to the URI_PTR construct 01072 ** 01073 ** @return integer 01074 ** 01075 ** @retval HI_SUCCESS function successful 01076 */ 01077 static int SetProxy(HI_SESSION *Session, u_char *start, 01078 u_char *end, u_char **ptr, URI_PTR *uri_ptr) 01079 { 01080 HTTPINSPECT_CONF *ServerConf = Session->server_conf; 01081 01082 if(!uri_ptr->ident && !uri_ptr->last_dir) 01083 { 01084 if(Session->global_conf->proxy_alert && !ServerConf->allow_proxy) 01085 { 01086 if(hi_util_in_bounds(start, end, ((*ptr)+2))) 01087 { 01088 if(*((*ptr)+1) == '/' && *((*ptr)+1) == '/') 01089 { 01090 uri_ptr->proxy = *ptr; 01091 } 01092 } 01093 } 01094 } 01095 01096 (*ptr)++; 01097 01098 return HI_SUCCESS; 01099 } 01100 01101 /* 01102 ** NAME 01103 ** SetClientVars:: 01104 */ 01105 /** 01106 ** This is where we set the HI_CLIENT values that we found during URI 01107 ** discovery. This also covers checking these values for errors. 01108 ** 01109 ** @param Client pointer to HI_CLIENT structure 01110 ** @param uri_ptr pointer to the uri data 01111 ** 01112 ** @return integer 01113 ** 01114 ** @retval HI_NONFATAL_ERR problem with the uri values. 01115 ** @retval HI_SUCCESS values set successfully 01116 */ 01117 static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize) 01118 { 01119 /* 01120 ** We got here either because we found the delimiter or we are 01121 ** out of bounds. 01122 */ 01123 01124 /* 01125 if(uri_ptr->first_sp_start) 01126 printf("** first_start = %c\n", *uri_ptr->first_sp_start); 01127 if(uri_ptr->first_sp_end) 01128 printf("** first_end = %c\n", *uri_ptr->first_sp_end); 01129 if(uri_ptr->second_sp_start) 01130 printf("** second_start = %c\n", *uri_ptr->second_sp_start); 01131 if(uri_ptr->second_sp_end) 01132 printf("** second_end = %c\n", *uri_ptr->second_sp_end); 01133 if(uri_ptr->delimiter) 01134 printf("** delimiter = %c\n", *uri_ptr->delimiter); 01135 01136 if(uri_ptr->uri) 01137 printf("** uri = %c\n", *uri_ptr->uri); 01138 if(uri_ptr->norm) 01139 printf("** norm = %.2x\n", *uri_ptr->norm); 01140 */ 01141 01142 /* 01143 ** This means that there was only spaces or delimiters within the 01144 ** complete URI. In this case, there is no valid URI so we just 01145 ** return such. 01146 */ 01147 if(uri_ptr->uri == NULL) 01148 { 01149 return HI_NONFATAL_ERR; 01150 } 01151 01152 /* 01153 ** This is where we set the Session variables before moving into more 01154 ** HttpInspect processing. If we don't get to this point, then we don't 01155 ** need to set these variables since we would have aborted with a 01156 ** NONFATAL_ERR. 01157 */ 01158 Client->request.uri = uri_ptr->uri; 01159 Client->request.uri_size = uri_ptr->uri_end - uri_ptr->uri; 01160 Client->request.uri_norm = uri_ptr->norm; 01161 01162 /* 01163 ** LAST RESORT: 01164 ** 01165 ** This is one of the last checks we do to make sure that we didn't 01166 ** mess up or anything. 01167 */ 01168 if(Client->request.uri_size < 1 || Client->request.uri_size > dsize) 01169 { 01170 /* 01171 ** Bad stuff, let's just bail. 01172 */ 01173 return HI_NONFATAL_ERR; 01174 } 01175 01176 /* 01177 printf("** Norm = %s\n", Client->request.uri_norm ? "YES" : "NO"); 01178 printf("** URI: |%.*s| size = %u\n", Client->request.uri_size, 01179 Client->request.uri, Client->request.uri_size); 01180 */ 01181 01182 return HI_SUCCESS; 01183 } 01184 01185 /* 01186 ** NAME 01187 ** StatelessInspection:: 01188 */ 01189 /** 01190 ** Find the URI and determine whether the URI needs to be normalized. 01191 ** 01192 ** This is a big step in stateless inspection, because we need to reliably 01193 ** find the URI and when possible filter out non-URIs. We do this using a 01194 ** simple state machine that is based on characters found in the data 01195 ** buffer. 01196 ** 01197 ** Another important aspect of the stateless inspection is the ability to 01198 ** track and inspect pipelined requests. It is VERY IMPORTANT to reset the 01199 ** pipeline_req pointer, since we don't memset the whole structure. This 01200 ** pointer is reset in the hi_si_session_inspection() function. Check there 01201 ** for more details. 01202 ** 01203 ** Normalization is detected when we are looking at the packet for the URI. 01204 ** We look for the following issues: 01205 ** - //// 01206 ** - /../ 01207 ** - /./ 01208 ** - non-ascii charss 01209 ** - % 01210 ** - \ 01211 ** When these things are seen we point to the first occurence in the URI, or 01212 ** where we have to start normalizing. If the URI is updated to a new 01213 ** pointer, then the normalization pointer is reset and we start over. 01214 ** Using this method should cut down the memcpy()s per URI, since most 01215 ** URIs are not normalized. 01216 ** 01217 ** If this function returns HI_NONFATAL_ERR, we return out of mode_inspection 01218 ** with an error and abort HttpInspect processing, and continue on with 01219 ** any other processing we do. The Session parameters that we use here are 01220 ** reset in the next time that we do session_inspection, so we don't do 01221 ** any initialization here. 01222 ** 01223 ** @param Session pointer to the HTTP session 01224 ** @param data pointer to the start of the packet payload 01225 ** @param dsize size of the payload 01226 ** 01227 ** @return integer 01228 ** 01229 ** @retval HI_INVALID_ARG invalid argument 01230 ** @retval HI_NONFATAL_ERR no URI detected 01231 ** @retval HI_SUCCESS URI detected and Session pointers updated 01232 */ 01233 static int StatelessInspection(HI_SESSION *Session, unsigned char *data, 01234 int dsize) 01235 { 01236 HTTPINSPECT_CONF *ServerConf; 01237 HTTPINSPECT_CONF *ClientConf; 01238 HI_CLIENT *Client; 01239 URI_PTR uri_ptr; 01240 u_char *start; 01241 u_char *end; 01242 u_char *ptr; 01243 int iRet; 01244 01245 if(!Session || !data || dsize < 1) 01246 { 01247 return HI_INVALID_ARG; 01248 } 01249 01250 ServerConf = Session->server_conf; 01251 if(!ServerConf) 01252 { 01253 return HI_INVALID_ARG; 01254 } 01255 01256 ClientConf = Session->client_conf; 01257 if(!ClientConf) 01258 { 01259 return HI_INVALID_ARG; 01260 } 01261 01262 Client = &Session->client; 01263 01264 memset(&uri_ptr, 0x00, sizeof(URI_PTR)); 01265 01266 /* 01267 ** We set the starting boundary depending on whether this request is 01268 ** a normal request or a pipeline request. The end boundary is always 01269 ** the same whether it is a pipeline request or other. 01270 */ 01271 if(Client->request.pipeline_req) 01272 { 01273 start = Client->request.pipeline_req; 01274 } 01275 else 01276 { 01277 start = data; 01278 } 01279 01280 end = data + dsize; 01281 01282 ptr = start; 01283 01284 /* 01285 ** Apache and IIS strike again . . . Thanks Kanatoko 01286 ** - Ignore CRLFs at the beginning of the request. 01287 */ 01288 while(hi_util_in_bounds(start, end, ptr)) 01289 { 01290 if(*ptr < 0x21) 01291 { 01292 if(*ptr < 0x0E && *ptr > 0x08) 01293 { 01294 ptr++; 01295 continue; 01296 } 01297 else 01298 { 01299 if(*ptr == 0x20) 01300 { 01301 ptr++; 01302 continue; 01303 } 01304 } 01305 } 01306 01307 break; 01308 } 01309 01310 uri_ptr.uri = ptr; 01311 uri_ptr.uri_end = end; 01312 01313 /* 01314 ** This loop compares each char to an array of functions 01315 ** (one for each char) and calling that function if there is one. 01316 ** 01317 ** If there is no function, then we just increment the char ptr and 01318 ** continue processing. 01319 ** 01320 ** If there is a function, we call that function and process. It's 01321 ** important to note that the function that is called is responsible 01322 ** for incrementing the ptr to the next char to be inspected. The 01323 ** loop does not increment the pointer when a function is called to 01324 ** allow the maximum flexibility to the functions. 01325 */ 01326 while(hi_util_in_bounds(start, end, ptr)) 01327 { 01328 if(lookup_table[*ptr]) 01329 { 01330 if((iRet = (lookup_table[*ptr])(Session, start, end, 01331 &ptr, &uri_ptr))) 01332 { 01333 if(iRet == URI_END) 01334 { 01335 /* 01336 ** You found a URI, let's break and check it out. 01337 */ 01338 break; 01339 } 01340 else if(iRet == HI_OUT_OF_BOUNDS) 01341 { 01342 /* 01343 ** Means you've reached the end of the buffer. THIS 01344 ** DOESN'T MEAN YOU HAVEN'T FOUND A URI. 01345 */ 01346 break; 01347 } 01348 else /* NO_URI */ 01349 { 01350 /* 01351 ** Check for chunk encoding, because the delimiter can 01352 ** also be a space, which would look like a pipeline request 01353 ** to us if we don't do this first. 01354 */ 01355 if(Session->server_conf->chunk_length) 01356 CheckChunkEncoding(Session, start, end); 01357 01358 /* 01359 ** We only inspect the packet for another pipeline 01360 ** request if there wasn't a previous pipeline request. 01361 ** The reason that we do this is because 01362 */ 01363 if(!Client->request.pipeline_req) 01364 { 01365 /* 01366 ** Just because there was no URI in the first part 01367 ** the packet, doesn't mean that this isn't a 01368 ** pipelined request that has been segmented. 01369 */ 01370 if(!ServerConf->no_pipeline) 01371 { 01372 if((Client->request.pipeline_req = 01373 FindPipelineReq(ptr, end))) 01374 { 01375 return HI_SUCCESS; 01376 } 01377 } 01378 } 01379 01380 return HI_NONFATAL_ERR; 01381 } 01382 } 01383 else 01384 { 01385 /* 01386 ** This means that we found the next non-whitespace char 01387 ** and since we are already pointed there, so we just 01388 ** continue. 01389 */ 01390 continue; 01391 } 01392 } 01393 01394 ptr++; 01395 } 01396 01397 /* 01398 ** If there is a pipelined request in this packet, we should always 01399 ** see the first space followed by text (which is the URI). Without 01400 ** that first space, then we never get to the URI, so we should just 01401 ** return, since there is nothing else to inspect. 01402 */ 01403 if(Client->request.pipeline_req) 01404 { 01405 if(uri_ptr.uri != uri_ptr.first_sp_end) 01406 { 01407 if(Session->server_conf->chunk_length) 01408 CheckChunkEncoding(Session, start, end); 01409 01410 return HI_NONFATAL_ERR; 01411 } 01412 } 01413 01414 /* 01415 ** We set the HI_CLIENT variables from the URI_PTR structure. We also 01416 ** do error checking for the values in this routine as well. 01417 */ 01418 if((iRet = SetClientVars(Client, &uri_ptr, dsize))) 01419 { 01420 return iRet; 01421 } 01422 01423 /* 01424 ** One last check for an oversize directory. This gets the long 01425 ** directory when there is a beginning slash and no other slashes 01426 ** until the end of the packet. 01427 ** 01428 ** We do this check after we set the variables, just in case there 01429 ** was some errors while setting the variables. This could save some 01430 ** false positives on a bad URI setting. 01431 */ 01432 if(uri_ptr.uri_end) 01433 CheckLongDir(Session, &uri_ptr, uri_ptr.uri_end); 01434 01435 /* 01436 ** Check for absolute URI and alert for proxy comm if necessary 01437 ** 01438 ** NOTE: 01439 ** Also check ClientConf for proxy configuration so we don't 01440 ** alert on outbound requests from legitimate proxies. 01441 */ 01442 if(uri_ptr.proxy && Session->global_conf->proxy_alert && 01443 (!ServerConf->allow_proxy && !ClientConf->allow_proxy)) 01444 { 01445 if(hi_eo_generate_event(Session, HI_EO_CLIENT_PROXY_USE)) 01446 { 01447 hi_eo_client_event_log(Session, HI_EO_CLIENT_PROXY_USE, 01448 NULL, NULL); 01449 } 01450 } 01451 01452 /* 01453 ** Find the next pipeline request, if one is there. If we don't find 01454 ** a pipeline request, then we return NULL here, so this is always 01455 ** set to the correct value. 01456 */ 01457 if(!ServerConf->no_pipeline) 01458 { 01459 Client->request.pipeline_req = FindPipelineReq(uri_ptr.delimiter, end); 01460 } 01461 else 01462 { 01463 Client->request.pipeline_req = NULL; 01464 } 01465 01466 if(Session->server_conf->chunk_length) 01467 CheckChunkEncoding(Session, uri_ptr.delimiter, end); 01468 01469 return HI_SUCCESS; 01470 } 01471 01472 int hi_client_inspection(void *S, unsigned char *data, int dsize) 01473 { 01474 HTTPINSPECT_GLOBAL_CONF *GlobalConf; 01475 HI_SESSION *Session; 01476 01477 int iRet; 01478 01479 if(!S || !data || dsize < 1) 01480 { 01481 return HI_INVALID_ARG; 01482 } 01483 01484 Session = (HI_SESSION *)S; 01485 01486 if(!Session->global_conf) 01487 { 01488 return HI_INVALID_ARG; 01489 } 01490 01491 GlobalConf = Session->global_conf; 01492 01493 /* 01494 ** We inspect the HTTP protocol in either stateful mode or 01495 ** stateless mode. 01496 */ 01497 if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL) 01498 { 01499 /* 01500 ** This is where we do stateful inspection. 01501 */ 01502 return HI_NONFATAL_ERR; 01503 } 01504 else 01505 { 01506 /* 01507 ** Otherwise we assume stateless inspection 01508 */ 01509 if((iRet = StatelessInspection(Session, data, dsize))) 01510 { 01511 return iRet; 01512 } 01513 } 01514 01515 return HI_SUCCESS; 01516 } 01517 01518 /* 01519 ** NAME 01520 ** hi_client_init:: 01521 */ 01522 /** 01523 ** Initializes arrays and search algorithms depending on the type of 01524 ** inspection that we are doing. 01525 ** 01526 ** @param GlobalConf pointer to the global configuration 01527 ** 01528 ** @return integer 01529 ** 01530 ** @retval HI_SUCCESS function successful. 01531 */ 01532 int hi_client_init(HTTPINSPECT_GLOBAL_CONF *GlobalConf) 01533 { 01534 int iCtr; 01535 int iNum; 01536 01537 if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL) 01538 { 01539 /* 01540 ** We don't have to do anything here yet. 01541 */ 01542 } 01543 else 01544 { 01545 memset(lookup_table, 0x00, sizeof(lookup_table)); 01546 memset(hex_lookup, -1, sizeof(hex_lookup)); 01547 01548 /* 01549 ** Set up the non-ASCII register for processing. 01550 */ 01551 for(iCtr = 0x80; iCtr <= 0xff; iCtr++) 01552 { 01553 lookup_table[iCtr] = SetBinaryNorm; 01554 } 01555 lookup_table[0x00] = SetBinaryNorm; 01556 01557 lookup_table[' '] = NextNonWhiteSpace; 01558 lookup_table['\t'] = NextNonWhiteSpace; 01559 lookup_table['\r'] = find_rfc_delimiter; 01560 lookup_table['\n'] = find_non_rfc_delimiter; 01561 01562 /* 01563 ** ASCII encoding 01564 */ 01565 lookup_table['%'] = SetPercentNorm; 01566 01567 /* 01568 ** Looking for multiple slashes 01569 */ 01570 lookup_table['/'] = SetSlashNorm; 01571 01572 /* 01573 ** Looking for backslashs 01574 */ 01575 lookup_table['\\'] = SetBackSlashNorm; 01576 01577 /* 01578 ** Look up parameter field, so we don't alert on long directory 01579 ** strings, when the next slash in the parameter field. 01580 */ 01581 lookup_table['?'] = SetParamField; 01582 01583 /* 01584 ** Look for absolute URI and proxy communication. 01585 */ 01586 lookup_table[':'] = SetProxy; 01587 01588 /* 01589 ** Set up the hex array 01590 */ 01591 iNum = 0; 01592 for(iCtr = 48; iCtr < 58; iCtr++) 01593 { 01594 hex_lookup[iCtr] = iNum; 01595 iNum++; 01596 } 01597 01598 /* 01599 ** Set the upper case values. 01600 */ 01601 iNum = 10; 01602 for(iCtr = 65; iCtr < 71; iCtr++) 01603 { 01604 hex_lookup[iCtr] = iNum; 01605 iNum++; 01606 } 01607 01608 /* 01609 ** Set the lower case values. 01610 */ 01611 iNum = 10; 01612 for(iCtr = 97; iCtr < 103; iCtr++) 01613 { 01614 hex_lookup[iCtr] = iNum; 01615 iNum++; 01616 } 01617 } 01618 01619 return HI_SUCCESS; 01620 } 01621 01622 01623 01624 /** 01625 ** This was just an initial testing program for these functions. 01626 */ 01627 #ifdef TEST_ME 01628 01629 #include <sys/socket.h> 01630 #include <netinet/in.h> 01631 #include <arpa/inet.h> 01632 01633 int main(int argc, char **argv) 01634 { 01635 HTTPINSPECT_GLOBAL_CONF GlobalConf; 01636 HI_SESSION *Session; 01637 HI_SI_INPUT SiInput; 01638 int iInspectMode = 0; 01639 int iRet; 01640 char data[] = "Hdslkfjaslfkj HTTP/00000.111111"; 01641 01642 if((iRet = hi_ui_config_init_global_conf(&GlobalConf))) 01643 { 01644 printf("** error during global init.\n"); 01645 return iRet; 01646 } 01647 01648 if((iRet = hi_ui_config_default(&GlobalConf))) 01649 { 01650 printf("** error config default.\n"); 01651 return iRet; 01652 } 01653 01654 hi_ui_config_print_config(&GlobalConf); 01655 01656 if((iRet = hi_client_init(&GlobalConf))) 01657 { 01658 printf("** error client init\n"); 01659 return iRet; 01660 } 01661 01662 SiInput.sip = inet_addr("1.1.1.1"); 01663 SiInput.sip = inet_addr("1.1.1.2"); 01664 SiInput.dport = 80; 01665 SiInput.sport = 7880; 01666 01667 if((iRet = hi_si_session_inspection(&GlobalConf, &Session, &SiInput, 01668 &iInspectMode))) 01669 { 01670 printf("** error session inspection\n"); 01671 return iRet; 01672 } 01673 01674 printf("** iInspectMode = %d\n", iInspectMode); 01675 if((iRet = hi_mi_mode_inspection(Session, iInspectMode, data, 01676 strlen(data)))) 01677 { 01678 printf("** error mode_inspection\n"); 01679 return iRet; 01680 } 01681 01682 return 0; 01683 } 01684 #endif 01685 01686