Normalization for http_cookie is the same URI-style normalization applied
to http_header when no specific header is specified.
+===== http_true_ip
+
+This provides the original IP address of the client sending the request as
+it was stored by a proxy in the request message headers. Specifically it
+is the last IP address listed in the X-Forwarded-For or True-Client-IP
+header. If both headers are present the former is used.
+
===== http_client_body
This is the body of a request message such as POST or PUT. Normalization
"http_stat_code",
"http_stat_msg",
"http_trailer",
+ "http_true_ip",
"http_uri",
"http_version",
nullptr
extern const BaseApi* ips_http_stat_code;
extern const BaseApi* ips_http_stat_msg;
extern const BaseApi* ips_http_trailer;
+extern const BaseApi* ips_http_true_ip;
extern const BaseApi* ips_http_uri;
extern const BaseApi* ips_http_version;
ips_http_stat_code,
ips_http_stat_msg,
ips_http_trailer,
+ ips_http_true_ip,
ips_http_uri,
ips_http_version,
nullptr
enum HTTP_BUFFER { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFER_HEADER,
HTTP_BUFFER_METHOD, HTTP_BUFFER_RAW_BODY, HTTP_BUFFER_RAW_COOKIE, HTTP_BUFFER_RAW_HEADER,
HTTP_BUFFER_RAW_REQUEST, HTTP_BUFFER_RAW_STATUS, HTTP_BUFFER_RAW_TRAILER, HTTP_BUFFER_RAW_URI,
- HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG, HTTP_BUFFER_TRAILER, HTTP_BUFFER_URI,
- HTTP_BUFFER_VERSION, HTTP_BUFFER_MAX };
+ HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG, HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP,
+ HTTP_BUFFER_URI, HTTP_BUFFER_VERSION, HTTP_BUFFER_MAX };
// Peg counts
// This enum must remain synchronized with HttpModule::peg_names[] in http_tables.cc
HttpMsgHeader* const req_header = transaction->get_header(SRC_CLIENT);
if (req_header == nullptr)
return 0;
- const Field& true_ip = req_header->get_true_ip();
+ const Field& true_ip = req_header->get_true_ip_addr();
if (true_ip.length() <= 0)
return 0;
}
}
- // This is potentially a comma-separated list of IP addresses. Just take the first one in
- // the list. Since this is a normalized header field any whitespace will be an actual space.
- uint8_t* addr_str = new uint8_t[header_to_use->length()+1];
+ // This is potentially a comma-separated list of IP addresses. Take the last one in the list.
+ // Since this is a normalized header field any whitespace will be an actual space.
int32_t length;
for (length = 0; length < header_to_use->length(); length++)
{
- if (is_sp_comma[header_to_use->start()[length]])
+ if (is_sp_comma[header_to_use->start()[header_to_use->length() - length - 1]])
break;
- addr_str[length] = header_to_use->start()[length];
}
- addr_str[length] = '\0';
+
+ true_ip.set(length, header_to_use->start() + (header_to_use->length() - length));
+ return true_ip;
+}
+
+const Field& HttpMsgHeader::get_true_ip_addr()
+{
+ if (true_ip_addr.length() != STAT_NOT_COMPUTE)
+ return true_ip_addr;
+
+ const Field& true_ip = get_true_ip();
+ if (true_ip.length() <= 0)
+ {
+ true_ip_addr.set(STAT_NOT_PRESENT);
+ return true_ip_addr;
+ }
+
+ // Need a temporary copy so we can add null termination
+ uint8_t* addr_str = new uint8_t[true_ip.length()+1];
+ memcpy(addr_str, true_ip.start(), true_ip.length());
+ addr_str[true_ip.length()] = '\0';
SfIp tmp_sfip;
const SfIpRet status = tmp_sfip.set((char*)addr_str);
delete[] addr_str;
if (status != SFIP_SUCCESS)
{
- true_ip.set(STAT_PROBLEMATIC);
+ true_ip_addr.set(STAT_PROBLEMATIC);
}
else
{
const size_t addr_length = (tmp_sfip.is_ip6() ? 4 : 1);
uint32_t* const addr_buf = new uint32_t[addr_length];
memcpy(addr_buf, tmp_sfip.get_ptr(), addr_length * sizeof(uint32_t));
- true_ip.set(addr_length * sizeof(uint32_t), (uint8_t*)addr_buf, true);
+ true_ip_addr.set(addr_length * sizeof(uint32_t), (uint8_t*)addr_buf, true);
}
- return true_ip;
+ return true_ip_addr;
}
void HttpMsgHeader::gen_events()
HttpApi::classic_buffer_names[HTTP_BUFFER_COOKIE-1]);
get_classic_buffer(HTTP_BUFFER_HEADER, 0, 0).print(output,
HttpApi::classic_buffer_names[HTTP_BUFFER_HEADER-1]);
+ if (source_id == SRC_CLIENT)
+ {
+ get_classic_buffer(HTTP_BUFFER_TRUE_IP, 0, 0).print(output,
+ HttpApi::classic_buffer_names[HTTP_BUFFER_TRUE_IP-1]);
+ }
get_classic_buffer(HTTP_BUFFER_RAW_COOKIE, 0, 0).print(output,
HttpApi::classic_buffer_names[HTTP_BUFFER_RAW_COOKIE-1]);
get_classic_buffer(HTTP_BUFFER_RAW_HEADER, 0, 0).print(output,
void gen_events() override;
void publish() override;
const Field& get_true_ip();
+ const Field& get_true_ip_addr();
private:
// Dummy configurations to support MIME processing
bool detection_section = true;
Field true_ip;
+ Field true_ip_addr;
#ifdef REG_TEST
void print_section(FILE* output) override;
HttpMsgStatus* status = transaction->get_status();
return (status != nullptr) ? status->get_reason_phrase() : Field::FIELD_NULL;
}
+ case HTTP_BUFFER_TRUE_IP:
+ {
+ HttpMsgHeader* header = transaction->get_header(SRC_CLIENT);
+ return (header != nullptr) ? header->get_true_ip() : Field::FIELD_NULL;
+ }
case HTTP_BUFFER_URI:
case HTTP_BUFFER_RAW_URI:
{
case HTTP_BUFFER_RAW_URI:
case HTTP_BUFFER_STAT_CODE:
case HTTP_BUFFER_STAT_MSG:
+ case HTTP_BUFFER_TRUE_IP:
case HTTP_BUFFER_URI:
case HTTP_BUFFER_VERSION:
inspect_section = IS_DETECTION;
nullptr
};
+//-------------------------------------------------------------------------
+// http_true_ip
+//-------------------------------------------------------------------------
+
+static const Parameter http_true_ip_params[] =
+{
+ { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+ "parts of this rule examine HTTP message body" },
+ { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
+ "parts of this rule examine HTTP message trailers" },
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_true_ip"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the final client IP address"
+
+static Module* true_ip_mod_ctor()
+{
+ return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER,
+ PSI_TRUE_IP, http_true_ip_params);
+}
+
+static const IpsApi true_ip_api =
+{
+ {
+ PT_IPS_OPTION,
+ sizeof(IpsApi),
+ IPSAPI_VERSION,
+ 1,
+ API_RESERVED,
+ API_OPTIONS,
+ IPS_OPT,
+ IPS_HELP,
+ true_ip_mod_ctor,
+ HttpCursorModule::mod_dtor
+ },
+ OPT_TYPE_DETECTION,
+ 0, PROTO_BIT__TCP,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ HttpIpsOption::opt_ctor,
+ HttpIpsOption::opt_dtor,
+ nullptr
+};
+
//-------------------------------------------------------------------------
// http_uri
//-------------------------------------------------------------------------
const BaseApi* ips_http_stat_code = &stat_code_api.base;
const BaseApi* ips_http_stat_msg = &stat_msg_api.base;
const BaseApi* ips_http_trailer = &trailer_api.base;
+const BaseApi* ips_http_true_ip = &true_ip_api.base;
const BaseApi* ips_http_uri = &uri_api.base;
const BaseApi* ips_http_version = &version_api.base;
enum PsIdx { PSI_CLIENT_BODY, PSI_COOKIE, PSI_HEADER, PSI_METHOD, PSI_RAW_BODY, PSI_RAW_COOKIE,
PSI_RAW_HEADER, PSI_RAW_REQUEST, PSI_RAW_STATUS, PSI_RAW_TRAILER, PSI_RAW_URI, PSI_STAT_CODE,
- PSI_STAT_MSG, PSI_TRAILER, PSI_URI, PSI_VERSION, PSI_MAX };
+ PSI_STAT_MSG, PSI_TRAILER, PSI_TRUE_IP, PSI_URI, PSI_VERSION, PSI_MAX };
class HttpCursorModule : public Module
{