Optimization on the status engine call

The status string was too long. By removing meaningless stuff, such as: runtime
version of Lua, we have reduced the length of the status string. Limitations
were also placed regarding the size of the ModSecurity version. Big queries may
lead to failure, due to restrictions of "gethostbyname". There is also a bit of
code cosmetics in this patch: big functions were broken into smaller.
This commit is contained in:
Felipe Zimmerle 2014-02-26 05:57:07 -08:00
parent 20014c808c
commit 410aca9d78
2 changed files with 209 additions and 143 deletions

View File

@ -29,8 +29,8 @@
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#if ! defined(IFT_ETHER) #ifndef IFT_ETHER
#define IFT_ETHER 0x6/* Ethernet CSMACD */ #define IFT_ETHER 0x6 /* Ethernet CSMACD */
#endif #endif
#endif #endif
@ -40,9 +40,10 @@
#include <linux/sockios.h> #include <linux/sockios.h>
#endif #endif
// Bese32 encode, based on: // Bese32 encode, based on:
// https://code.google.com/p/google-authenticator/source/browse/libpam/base32.c // https://code.google.com/p/google-authenticator/source/browse/libpam/base32.c
void DSOLOCAL msc_status_engine_base32_encode(char *encoded, int DSOLOCAL msc_status_engine_base32_encode(char *encoded,
const char *data, int len) { const char *data, int len) {
int buffer; int buffer;
int count = 0; int count = 0;
@ -51,6 +52,11 @@ void DSOLOCAL msc_status_engine_base32_encode(char *encoded,
buffer = data[0]; buffer = data[0];
if (encoded == NULL && len == 0) {
len = length * 3;
count++;
}
if (length > 0) { if (length > 0) {
int next = 1; int next = 1;
int bitsLeft = 8; int bitsLeft = 8;
@ -69,20 +75,38 @@ void DSOLOCAL msc_status_engine_base32_encode(char *encoded,
} }
index = 0x1f & (buffer >> (bitsLeft - 5)); index = 0x1f & (buffer >> (bitsLeft - 5));
bitsLeft -= 5; bitsLeft -= 5;
result[count++] = msc_status_engine_basis_32[index]; if (encoded != NULL) {
result[count] = msc_status_engine_basis_32[index];
}
count++;
} }
} }
if (count < len) { if (count < len && encoded != NULL) {
result[count] = '\000'; result[count] = '\000';
} }
return count;
} }
void DSOLOCAL msc_status_engine_fill_with_dots(char *encoded_with_dots, int DSOLOCAL msc_status_engine_fill_with_dots(char *encoded_with_dots,
const char *data, int len, int space) const char *data, int len, int space)
{ {
int i; int i;
int count = 0; int count = 0;
if (encoded_with_dots == NULL) {
if (len == 0 && data != NULL) {
len = strlen(data);
}
else if (len == 0 && data == NULL) {
count = -1;
goto return_length;
}
count = len/space + len + 1;
goto return_length;
}
for (i = 0; i < strlen(data) && i < len; i++) { for (i = 0; i < strlen(data) && i < len; i++) {
if (i % space == 0 && i != 0) { if (i % space == 0 && i != 0) {
encoded_with_dots[count++] = '.'; encoded_with_dots[count++] = '.';
@ -90,6 +114,9 @@ void DSOLOCAL msc_status_engine_fill_with_dots(char *encoded_with_dots,
encoded_with_dots[count++] = data[i]; encoded_with_dots[count++] = data[i];
} }
encoded_with_dots[count] = '\0'; encoded_with_dots[count] = '\0';
return_length:
return count;
} }
@ -103,7 +130,9 @@ int DSOLOCAL msc_status_engine_machine_name(char *machine_name, size_t len) {
memset(machine_name, '\0', sizeof(char) * len); memset(machine_name, '\0', sizeof(char) * len);
#ifdef WIN32 #ifdef WIN32
GetComputerName(machine_name, &lenComputerName); if (GetComputerName(machine_name, &lenComputerName) == 0) {
goto failed;
}
#else #else
static struct utsname u; static struct utsname u;
@ -136,10 +165,15 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr; struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ) if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER )
&& mac[0] && mac[1] && mac[2] && i < 6) { && mac[0] && mac[1] && mac[2] && i < 6) {
for (i = 0; i<6; i++) {
sprintf(mac, "%s%s%02x", mac, (i == 0)?"":":", apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned char)LLADDR(sdl)[i]); (unsigned char)LLADDR(sdl)[0],
} (unsigned char)LLADDR(sdl)[1],
(unsigned char)LLADDR(sdl)[2],
(unsigned char)LLADDR(sdl)[3],
(unsigned char)LLADDR(sdl)[4],
(unsigned char)LLADDR(sdl)[5]);
goto end;
} }
} }
@ -175,10 +209,15 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
continue; continue;
} }
for (i = 0; i<6; i++) { apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
sprintf(mac, "%s%s%02x", mac, (i == 0)?"":":", (unsigned char)ifr->ifr_addr.sa_data[0],
(unsigned char)ifr->ifr_addr.sa_data[i]); (unsigned char)ifr->ifr_addr.sa_data[1],
} (unsigned char)ifr->ifr_addr.sa_data[2],
(unsigned char)ifr->ifr_addr.sa_data[3],
(unsigned char)ifr->ifr_addr.sa_data[4],
(unsigned char)ifr->ifr_addr.sa_data[5]);
goto end;
} }
} }
close( sock ); close( sock );
@ -215,11 +254,14 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
{ {
if (pAdapter->AddressLength > 4) if (pAdapter->AddressLength > 4)
{ {
for (i = 0; i < pAdapter->AddressLength && i < 6; i++) apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
{ (unsigned char)pAdapter->Address[0],
sprintf(mac, "%s%s%02x", mac, (i == 0) ? "" : ":", (unsigned char)pAdapter->Address[1],
(unsigned char)pAdapter->Address[i]); (unsigned char)pAdapter->Address[2],
} (unsigned char)pAdapter->Address[3],
(unsigned char)pAdapter->Address[4],
(unsigned char)pAdapter->Address[5]);
goto end;
} }
pAdapter = pAdapter->Next; pAdapter = pAdapter->Next;
} }
@ -227,206 +269,226 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
free(pAdapterInfo); free(pAdapterInfo);
#endif #endif
done: end:
return 0; return 0;
failed: failed:
return -1; return -1;
} }
int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest) int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest)
{ {
unsigned char local_digest[APR_SHA1_DIGESTSIZE]; unsigned char hex_digest[APR_SHA1_DIGESTSIZE];
apr_sha1_ctx_t context;
char *input;
int i = 0;
unsigned char *mac_address = NULL; unsigned char *mac_address = NULL;
char *machine_name = NULL; char *machine_name = NULL;
int ret = 0; int ret = 0;
int i = 0;
apr_sha1_ctx_t context;
mac_address = malloc(sizeof(char)*(6+5+1)); mac_address = malloc(sizeof(char)*(MAC_ADDRESS_SIZE));
if (!mac_address) { if (!mac_address) {
ret = -1; ret = -1;
goto failed_mac_address; goto failed_mac_address;
} }
memset(mac_address, 0, sizeof(char)*(6+5+1)); memset(mac_address, '\0', sizeof(char)*(MAC_ADDRESS_SIZE));
if (msc_status_engine_mac_address(mac_address)) { if (msc_status_engine_mac_address(mac_address)) {
ret = -1; ret = -1;
goto failed_set_mac_address; goto failed_set_mac_address;
} }
machine_name = malloc(sizeof(char)*201); machine_name = malloc(sizeof(char)*MAX_MACHINE_NAME_SIZE);
if (!machine_name) { if (!machine_name) {
ret = -1; ret = -1;
goto failed_machine_name; goto failed_machine_name;
} }
memset(machine_name, '\0', sizeof(char)*(MAX_MACHINE_NAME_SIZE));
if (msc_status_engine_machine_name(machine_name, 200)) { if (msc_status_engine_machine_name(machine_name, MAC_ADDRESS_SIZE)) {
ret = -1; ret = -1;
goto failed_set_machine_name; goto failed_set_machine_name;
} }
input = malloc(sizeof(char)*(strlen(machine_name) +
strlen(mac_address)+1));
if (!input) {
goto failed_input;
}
apr_snprintf(input, strlen(machine_name)+strlen(mac_address)+1,
"%s%s", machine_name, mac_address);
apr_sha1_init(&context); apr_sha1_init(&context);
apr_sha1_update(&context, input, strlen(input)); apr_sha1_update(&context, machine_name, strlen(machine_name));
apr_sha1_final(local_digest, &context); apr_sha1_update(&context, mac_address, strlen(mac_address));
apr_sha1_final(hex_digest, &context);
for (i = 0; i < APR_SHA1_DIGESTSIZE; i++) { for (i = 0; i < APR_SHA1_DIGESTSIZE; i++)
sprintf(digest, "%s%02x", digest, local_digest[i]); {
sprintf(digest, "%s%02x", digest, hex_digest[i]);
} }
free(input);
failed_input:
failed_set_machine_name: failed_set_machine_name:
free(machine_name); free(machine_name);
failed_machine_name: failed_machine_name:
failed_set_mac_address: failed_set_mac_address:
free(mac_address); free(mac_address);
failed_mac_address: failed_mac_address:
return ret; return ret;
} }
int msc_status_engine_call (void) { int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len) {
char *apr = NULL; char *apr = NULL;
const char *apr_loaded = NULL; const char *apr_loaded = NULL;
char pcre[7]; char pcre[7];
const char *pcre_loaded = NULL; const char *pcre_loaded = NULL;
char *lua = NULL; char *lua = NULL;
char *lua_loaded = NULL;
char *libxml = NULL; char *libxml = NULL;
char *libxml_loaded = NULL;
char *modsec = NULL; char *modsec = NULL;
const char *apache = NULL; const char *apache = NULL;
char *id = NULL; char id[(APR_SHA1_DIGESTSIZE*2) + 1];
char *beacon_string = NULL; int beacon_string_len = -1;
int beacon_string_len = 0;
char *beacon_string_encoded = NULL;
char *beacon_string_ready = NULL;
char *beacon_string_encoded_splitted = NULL;
int ret = 0;
apr = APR_VERSION_STRING; apr = APR_VERSION_STRING;
apr_loaded = apr_version_string(); apr_loaded = apr_version_string();
apr_snprintf(pcre, 7, "%d.%d", PCRE_MAJOR, PCRE_MINOR);
pcre_loaded = pcre_version(); pcre_loaded = pcre_version();
apr_snprintf(pcre, 7, "%2d.%2d ", PCRE_MAJOR, PCRE_MINOR);
#ifdef WITH_LUA #ifdef WITH_LUA
lua = LUA_VERSION; lua = LUA_VERSION;
#endif #endif
lua_loaded = 0;
libxml = LIBXML_DOTTED_VERSION; libxml = LIBXML_DOTTED_VERSION;
libxml_loaded = 0;
modsec = MODSEC_VERSION; modsec = MODSEC_VERSION;
apache = apache_get_server_version();
id = malloc(sizeof(char)*((2*APR_SHA1_DIGESTSIZE)+1));
if (!id) {
ret = -1;
goto failed_id;
}
memset(id, '\0', sizeof(char)*((2*APR_SHA1_DIGESTSIZE)+1));
if (msc_status_engine_unique_id(id)) {
sprintf(id, "unique id failed");
}
beacon_string_len = (modsec ? strlen(modsec) : 6) + (apache ? strlen(apache) : 6) +
(apr ? strlen(apr) : 6) + (apr_loaded ? strlen(apr_loaded) : 6) +
(pcre ? strlen(pcre) : 6) + (pcre_loaded ? strlen(pcre_loaded) : 6) +
(lua ? strlen(lua) : 6) + (lua_loaded ? strlen(lua_loaded) : 6) +
(libxml ? strlen(libxml) : 6) + (libxml_loaded ? strlen(libxml_loaded) : 6) +
(id ? strlen(id) : 6);
#ifdef WIN32 #ifdef WIN32
beacon_string = malloc(sizeof(char)*(beacon_string_len+1+10+4)); apache = "IIS";
if (!beacon_string) {
goto failed_beacon_string;
}
apr_snprintf(beacon_string, beacon_string_len+1+10+4,
"%s,IIS,%s/%s,%s/%s,%s/%s,%s/%s,%s",
modsec, apr, apr_loaded, pcre, pcre_loaded, lua, lua_loaded,
libxml, libxml_loaded, id);
#else #else
beacon_string = malloc(sizeof(char)*(beacon_string_len+1+10)); apache = apache_get_server_version();
if (!beacon_string) {
goto failed_beacon_string;
}
apr_snprintf(beacon_string, beacon_string_len+1+10,
"%s,%s,%s/%s,%s/%s,%s/%s,%s/%s,%s",
modsec, apache, apr, apr_loaded, pcre, pcre_loaded, lua, lua_loaded,
libxml, libxml_loaded, id);
#endif #endif
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, /* 6 represents: strlen("(null)") */
"ModSecurity: StatusEngine call: \"%s\"", beacon_string); beacon_string_len = (modsec ? strlen(modsec) : 6) +
(apache ? strlen(apache) : 6) + (apr ? strlen(apr) : 6) +
(apr_loaded ? strlen(apr_loaded) : 6) + (pcre ? strlen(pcre) : 6) +
(pcre_loaded ? strlen(pcre_loaded) : 6) + (lua ? strlen(lua) : 6) +
(libxml ? strlen(libxml) : 6) + (APR_SHA1_DIGESTSIZE * 2);
beacon_string_encoded = malloc(sizeof(char)*(strlen(beacon_string)*3)); beacon_string_len = beacon_string_len + /* null terminator: */ 1 +
if (!beacon_string_encoded) { /* comma: */ 6 +
goto failed_beacon_string_encoded; /* slash: */ 2;
}
msc_status_engine_base32_encode(beacon_string_encoded, beacon_string,
strlen(beacon_string)*3);
beacon_string_encoded_splitted = malloc (sizeof(char) * if (beacon_string == NULL || beacon_string_max_len == 0) {
((strlen(beacon_string_encoded)/STATUS_ENGINE_DNS_IN_BETWEEN_DOTS) + goto return_length;
strlen(beacon_string_encoded) + 1 + 1));
if (!beacon_string_encoded_splitted) {
goto failed_beacon_string_encoded_splitted;
} }
msc_status_engine_fill_with_dots(beacon_string_encoded_splitted, memset(id, '\0', sizeof(id));
beacon_string_encoded, if (msc_status_engine_unique_id(id)) {
(strlen(beacon_string_encoded)/STATUS_ENGINE_DNS_IN_BETWEEN_DOTS) + sprintf(id, "no unique id");
strlen(beacon_string_encoded) + 1 + 1, }
apr_snprintf(beacon_string, beacon_string_max_len,
"%.25s,%s,%s/%s,%s/%s,%s,%s,%s",
modsec, apache, apr, apr_loaded, pcre, pcre_loaded, lua, libxml, id);
return_length:
return beacon_string_len;
}
int DSOLOCAL msc_status_engine_prepare_hostname (char *hostname, const char *plain_data,
int max_length)
{
int str_enc_len = 0;
int str_enc_spl_len = 0;
char *tmp = NULL;
int length = -1;
time_t ltime;
str_enc_len = msc_status_engine_base32_encode(NULL, plain_data, 0);
str_enc_spl_len = msc_status_engine_fill_with_dots(NULL, NULL, str_enc_len,
STATUS_ENGINE_DNS_IN_BETWEEN_DOTS); STATUS_ENGINE_DNS_IN_BETWEEN_DOTS);
if (str_enc_spl_len < 0) {
beacon_string_ready = malloc (sizeof(char) * goto failed_enc_spl_len;
strlen(beacon_string_encoded_splitted) +
strlen(STATUS_ENGINE_DNS_SUFFIX) + 10 + 1);
if (!beacon_string_ready) {
goto failed_beacon_string_ready;
} }
apr_snprintf(beacon_string_ready, strlen(beacon_string_encoded_splitted) + length = str_enc_spl_len + strlen(STATUS_ENGINE_DNS_SUFFIX) +
strlen(STATUS_ENGINE_DNS_SUFFIX) + 12 + 1, "%s.%lu.%s", /* epoch: */ 10 + /* dots: */ 2 + /* terminator: */ 1 -
beacon_string_encoded_splitted, time(NULL), /* removed unsed terminators from str_enc and str_enc_spl: */ 2;
STATUS_ENGINE_DNS_SUFFIX);
if (gethostbyname(beacon_string_ready)) { if (hostname == NULL || max_length == 0) {
goto return_length;
}
memset(hostname, '\0', sizeof(char) * max_length);
msc_status_engine_base32_encode(hostname, plain_data, str_enc_len);
tmp = strdup(hostname);
if (tmp == NULL) {
length = -1;
goto failed_strdup;
}
str_enc_spl_len = msc_status_engine_fill_with_dots(hostname, tmp, max_length,
STATUS_ENGINE_DNS_IN_BETWEEN_DOTS);
if (str_enc_spl_len < 0) {
length = -1;
goto failed_enc_spl;
}
time ( &ltime );
apr_snprintf(hostname, max_length, "%s.%ld.%s", hostname,
(long) ltime, STATUS_ENGINE_DNS_SUFFIX);
failed_enc_spl:
free(tmp);
failed_strdup:
return_length:
failed_enc_spl_len:
return length;
}
int msc_status_engine_call (void) {
char *beacon_str = NULL;
int beacon_str_len = 0;
char *hostname = NULL;
int hostname_len = 0;
int ret = -1;
/* Retrieve the beacon string */
beacon_str_len = msc_beacon_string(NULL, 0);
beacon_str = malloc(sizeof(char) * beacon_str_len);
if (beacon_str == NULL) {
goto failed_beacon_string_malloc;
}
msc_beacon_string(beacon_str, beacon_str_len);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
"ModSecurity: StatusEngine call: \"%s\"", beacon_str);
/* Get beacon string in the format of a hostname */
hostname_len = msc_status_engine_prepare_hostname(NULL, beacon_str, 0);
if (hostname_len < 0) {
goto failed_hostname_len;
}
hostname = malloc(sizeof(char) * hostname_len);
if (hostname == NULL) {
goto failed_hostname_malloc;
}
hostname_len = msc_status_engine_prepare_hostname(hostname, beacon_str,
hostname_len);
if (hostname_len < 0) {
goto failed_hostname;
}
/* Perform the DNS query. */
if (gethostbyname(hostname)) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
"ModSecurity: StatusEngine call successfully sent. For more " \ "ModSecurity: StatusEngine call successfully sent. For more " \
"information visit: http://%s/", STATUS_ENGINE_DNS_SUFFIX); "information visit: http://%s/", STATUS_ENGINE_DNS_SUFFIX);
} else { } else {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
"ModSecurity: StatusEngine call failed. Query: %s", "ModSecurity: StatusEngine call failed. Query: %s",
beacon_string_ready); hostname);
} }
free(beacon_string_ready); ret = 0;
failed_beacon_string_ready:
free(beacon_string_encoded_splitted); failed_hostname:
failed_beacon_string_encoded_splitted: free(hostname);
free(beacon_string_encoded); failed_hostname_malloc:
failed_beacon_string_encoded: failed_hostname_len:
free(beacon_string); free(beacon_str);
failed_beacon_string: failed_beacon_string_malloc:
free(id);
failed_id:
return ret; return ret;
} }

View File

@ -29,6 +29,10 @@
#define STATUS_ENGINE_DNS_SUFFIX "status.modsecurity.org" #define STATUS_ENGINE_DNS_SUFFIX "status.modsecurity.org"
#define MAX_MACHINE_NAME_SIZE 100
#define MAC_ADDRESS_SIZE 20
static const char msc_status_engine_basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; static const char msc_status_engine_basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
int msc_status_engine_call(void); int msc_status_engine_call(void);