00001 /** 00002 ** @file hi_si.c 00003 ** 00004 ** @author Daniel J. Roelker <droelker@sourcefire.com> 00005 ** 00006 ** @brief This file contains functions to select server configurations 00007 ** and begin the HttpInspect process. 00008 ** 00009 ** The Session Inspection Module interfaces with the Stream Inspection 00010 ** Module and the User Interface Module to select the appropriate 00011 ** HttpInspect configuration and in the case of stateful inspection the 00012 ** Session Inspection Module retrieves the user-data from the Stream 00013 ** Module. For stateless inspection, the Session Inspection Module uses 00014 ** the same structure for use by each packet. 00015 ** 00016 ** The main responsibility of this module is to supply the appropriate 00017 ** data structures and configurations for the rest of the HttpInspect 00018 ** process. The module also determines what type of data is being 00019 ** inspected, whether it is client, server, or neither. 00020 ** 00021 ** NOTES: 00022 ** 00023 ** - 2.25.03: Initial Development. DJR 00024 */ 00025 #include <stdlib.h> 00026 #include <stdio.h> 00027 #include <string.h> 00028 00029 #include "hi_return_codes.h" 00030 #include "hi_ui_config.h" 00031 #include "hi_ui_server_lookup.h" 00032 #include "hi_si.h" 00033 #include "hi_ad.h" 00034 00035 /* 00036 ** NAME 00037 ** IsServer:: 00038 */ 00039 /** 00040 ** Given a server configuration and a port number, we decide if the port is 00041 ** in the HTTP server port list. 00042 ** 00043 ** @param ServerConf pointer to the server configuration 00044 ** @param port the port number to compare with the configuration 00045 ** @param pdir the packet direction (from client, server, etc.) 00046 ** 00047 ** @return integer 00048 ** 00049 ** @retval 0 means that the port is not a server port 00050 ** @retval !0 means that the port is a server port 00051 */ 00052 static int IsServer(HTTPINSPECT_CONF *ServerConf, unsigned short port) 00053 { 00054 if(ServerConf->ports[port]) 00055 { 00056 return 1; 00057 } 00058 00059 return 0; 00060 } 00061 00062 /* 00063 ** NAME 00064 ** InitServerConf:: 00065 */ 00066 /** 00067 ** When a session is initialized, we must select the appropriate server 00068 ** configuration and select the type of inspection based on the source and 00069 ** destination ports. 00070 ** 00071 ** IMPORTANT NOTE: 00072 ** We should check to make sure that there are some unique configurations, 00073 ** otherwise we can just default to the global default and work some magic 00074 ** that way. 00075 ** 00076 ** @param GlobalConf pointer to the global configuration 00077 ** @param ServerConf pointer to the address of the server config so we can 00078 ** set it. 00079 ** @param SiInput pointer to the packet info (sip,dip,sport,dport) 00080 ** @param piInspectMode pointer so we can set the inspection mode 00081 ** 00082 ** @return integer 00083 ** 00084 ** @retval HI_SUCCESS function successful 00085 */ 00086 static int InitServerConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf, 00087 HTTPINSPECT_CONF **ServerConf, 00088 HTTPINSPECT_CONF **ClientConf, 00089 HI_SI_INPUT *SiInput, int *piInspectMode) 00090 { 00091 HTTPINSPECT_CONF *ServerConfSip; 00092 HTTPINSPECT_CONF *ServerConfDip; 00093 int iServerSip; 00094 int iServerDip; 00095 int iErr = 0; 00096 00097 /* 00098 ** We find the server configurations for both the source and dest. IPs. 00099 ** There should be a check on the global configuration to see if there 00100 ** is at least one unique server configuration. If there isn't then we 00101 ** assume the global server configuration. 00102 */ 00103 ServerConfDip = hi_ui_server_lookup_find(GlobalConf->server_lookup, 00104 SiInput->dip, &iErr); 00105 if(!ServerConfDip) 00106 { 00107 ServerConfDip = &GlobalConf->global_server; 00108 } 00109 00110 ServerConfSip = hi_ui_server_lookup_find(GlobalConf->server_lookup, 00111 SiInput->sip, &iErr); 00112 if(!ServerConfSip) 00113 { 00114 ServerConfSip = &GlobalConf->global_server; 00115 } 00116 00117 /* 00118 ** We check the IP and the port to see if the HTTP server is talking in 00119 ** the session. This should tell us whether it is client communication 00120 ** or server configuration. If both IPs and ports are servers, then there 00121 ** is a sort of problem. We don't know which side is the client and which 00122 ** side is the server so we have to assume one. 00123 ** 00124 ** In stateful processing, we only do this stage on the startup of a 00125 ** session, so we can still assume that the initial packet is the client 00126 ** talking. 00127 */ 00128 iServerSip = IsServer(ServerConfSip, SiInput->sport); 00129 iServerDip = IsServer(ServerConfDip, SiInput->dport); 00130 00131 /* 00132 ** We default to the no HTTP traffic case 00133 */ 00134 *piInspectMode = HI_SI_NO_MODE; 00135 *ServerConf = NULL; 00136 00137 /* 00138 ** Depending on the type of packet direction we get from the 00139 ** state machine, we evaluate client/server differently. 00140 */ 00141 switch(SiInput->pdir) 00142 { 00143 case HI_SI_NO_MODE: 00144 /* 00145 ** We check for the case where both SIP and DIP 00146 ** appear to be servers. In this case, we assume client 00147 ** and process that way. 00148 */ 00149 if(iServerSip && iServerDip) 00150 { 00151 *piInspectMode = HI_SI_CLIENT_MODE; 00152 *ServerConf = ServerConfDip; 00153 *ClientConf = ServerConfSip; 00154 } 00155 else if(iServerSip) 00156 { 00157 *piInspectMode = HI_SI_SERVER_MODE; 00158 *ServerConf = ServerConfSip; 00159 *ClientConf = ServerConfDip; 00160 } 00161 else if(iServerDip) 00162 { 00163 *piInspectMode = HI_SI_CLIENT_MODE; 00164 *ServerConf = ServerConfDip; 00165 *ClientConf = ServerConfSip; 00166 } 00167 break; 00168 00169 case HI_SI_CLIENT_MODE: 00170 if(iServerDip) 00171 { 00172 *piInspectMode = HI_SI_CLIENT_MODE; 00173 *ServerConf = ServerConfDip; 00174 *ClientConf = ServerConfSip; 00175 } 00176 break; 00177 00178 case HI_SI_SERVER_MODE: 00179 if(iServerSip) 00180 { 00181 *piInspectMode = HI_SI_SERVER_MODE; 00182 *ServerConf = ServerConfSip; 00183 *ClientConf = ServerConfDip; 00184 } 00185 break; 00186 00187 default: 00188 *piInspectMode = HI_SI_NO_MODE; 00189 *ServerConf = NULL; 00190 *ClientConf = NULL; 00191 break; 00192 } 00193 00194 return HI_SUCCESS; 00195 } 00196 00197 static int StatefulSessionInspection(HTTPINSPECT_GLOBAL_CONF *GlobalConf, 00198 HI_SESSION **Session, HI_SI_INPUT *SiInput, int *piInspectType) 00199 { 00200 /* 00201 ** We do stuff here for stateful session inspection in the next phase. 00202 */ 00203 00204 return HI_NONFATAL_ERR; 00205 } 00206 00207 /* 00208 ** NAME 00209 ** ResetSession:: 00210 */ 00211 /** 00212 ** This function resets all the variables that need to be initialized for 00213 ** a new Session. I've tried to keep this to a minimum, so we don't have 00214 ** to worry about initializing big structures. 00215 ** 00216 ** @param Session pointer to the session to reset 00217 ** 00218 ** @return integer 00219 ** 00220 ** @retval HI_SUCCESS 00221 */ 00222 static INLINE int ResetSession(HI_SESSION *Session) 00223 { 00224 00225 Session->client.event_list.stack_count = 0; 00226 Session->anom_server.event_list.stack_count = 0; 00227 00228 Session->client.request.uri = NULL; 00229 Session->client.request.uri_norm = NULL; 00230 Session->client.request.uri_size = 0; 00231 Session->client.request.uri_norm_size = 0; 00232 00233 Session->client.request.pipeline_req = NULL; 00234 00235 return HI_SUCCESS; 00236 } 00237 00238 /* 00239 ** NAME 00240 ** StatelessSessionInspection:: 00241 */ 00242 /** 00243 ** Initialize the session and server configurations for this packet/stream. 00244 ** 00245 ** It is important to note in stateless mode that we assume no knowledge of the 00246 ** state of a connection, other than the knowledge that we can glean from an 00247 ** individual packet. So in essence, each packet is it's own session and there 00248 ** is no knowledge retained from one packet to another. If you want to track 00249 ** an HTTP session for real, use stateful mode. 00250 ** 00251 ** In this function, we set the Session pointer (which includes the correct 00252 ** server configuration). The actual processing to find which IP is the 00253 ** server and which is the client, is done in the InitServerConf() function. 00254 ** 00255 ** @param GlobalConf pointer to the global configuration 00256 ** @param Session double pointer to the Session structure 00257 ** @param SiInput pointer to the session information 00258 ** @param piInspectMode pointer so the inspection mode can be set 00259 ** 00260 ** @return integer 00261 ** 00262 ** @retval HI_SUCCESS function successful 00263 */ 00264 static int StatelessSessionInspection(HTTPINSPECT_GLOBAL_CONF *GlobalConf, 00265 HI_SESSION **Session, HI_SI_INPUT *SiInput, int *piInspectMode) 00266 { 00267 static HI_SESSION StaticSession; 00268 HTTPINSPECT_CONF *ServerConf; 00269 HTTPINSPECT_CONF *ClientConf; 00270 int iRet; 00271 00272 ResetSession(&StaticSession); 00273 00274 if((iRet = InitServerConf(GlobalConf, &ServerConf, &ClientConf, SiInput, 00275 piInspectMode))) 00276 { 00277 return iRet; 00278 } 00279 00280 StaticSession.server_conf = ServerConf; 00281 StaticSession.client_conf = ClientConf; 00282 StaticSession.global_conf = GlobalConf; 00283 00284 *Session = &StaticSession; 00285 00286 return HI_SUCCESS; 00287 } 00288 00289 00290 /* 00291 ** NAME 00292 ** hi_si_session_inspection:: 00293 */ 00294 /** 00295 ** The Session Inspection module selects the appropriate server configuration 00296 ** for the session, and the type of inspection to be performed (client or 00297 ** server.) 00298 ** 00299 ** When the Session Inspection module is in stateful mode, it checks to see if 00300 ** there is a HI_SESSION pointer already associated with the stream. If there 00301 ** is, then it uses that session pointer, otherwise it calculates the server 00302 ** configuration using the HI_SI_INPUT and returns a HI_SESSION pointer. In 00303 ** stateful mode, this means that memory is allocated, but in stateless mode, 00304 ** the same session pointer is used for all packets to reduce the allocation 00305 ** overhead. 00306 ** 00307 ** The inspection mode can be either client, server, or neither. In the case 00308 ** of neither, the packet is inspected for rogue HTTP servers and HTTP 00309 ** tunneling. 00310 ** 00311 ** @param GlobalConf pointer to the global configuration 00312 ** @param Session double pointer so the session can be set 00313 ** @param SiInput session input pointer for data 00314 ** @param piInspectMode pointer for setting inspection mode 00315 ** 00316 ** @return integer 00317 ** 00318 ** @retval HI_SUCCESS function successful 00319 ** @retval HI_MEM_ALLOC_FAIL failure to allocate memory 00320 ** @retval HI_INVALID_ARG argument was invalid (NULL pointers, etc) 00321 */ 00322 int hi_si_session_inspection(HTTPINSPECT_GLOBAL_CONF *GlobalConf, 00323 HI_SESSION **Session, HI_SI_INPUT *SiInput, int *piInspectMode) 00324 { 00325 int iRet; 00326 00327 /* 00328 ** We get the server configuration and the session structure differently 00329 ** depending on what type of inspection we are doing. In the case of 00330 ** stateful processing, we may get the session structure from the Stream 00331 ** Reassembly module (which includes the server configuration) or the 00332 ** structure will be allocated and added to the stream pointer for the 00333 ** rest of the session. 00334 ** 00335 ** In stateless mode, we just use a static variable that is contained in 00336 ** the function here. 00337 */ 00338 if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL) 00339 { 00340 if((iRet = StatefulSessionInspection(GlobalConf, Session, SiInput, 00341 piInspectMode))) 00342 { 00343 return iRet; 00344 } 00345 } 00346 else 00347 { 00348 /* 00349 ** Assume stateless processing otherwise 00350 */ 00351 if((iRet = StatelessSessionInspection(GlobalConf, Session, SiInput, 00352 piInspectMode))) 00353 { 00354 return iRet; 00355 } 00356 } 00357 00358 return HI_SUCCESS; 00359 }