📄 spo_xml.c
字号:
liberated from: spo_tcpdump.c */
bzero(timebuf, 10);
curr_time = time(NULL);
loc_time = localtime(&curr_time);
strftime(timebuf, 91, "%m%d@%H%M", loc_time);
if(d->file[0] != '/')
{
bzero(filename, STD_BUF);
if(chrootdir)
strncpy(filename, chrootdir, STD_BUF);
strncat(filename, pv.log_dir, STD_BUF - strlen(filename));
strncat(filename, "/", 1);
strncat(filename, d->file, STD_BUF - strlen(filename));
}
else
strncpy(filename, d->file, STD_BUF - strlen(filename));
strncat(filename, "-", STD_BUF - strlen(filename));
strncat(filename, timebuf, STD_BUF - strlen(filename));
/* Create unique filename to log to */
d->fptr = fopen(filename, "w");
/* Write XML header info */
fprintf(d->fptr, "%s", SNORTML_DECLARATION);
fprintf(d->fptr, "%s", SNORTML_DOCTYPE);
fprintf(d->fptr, "\n%s", SNORTML_FILE_BEGIN);
if(!d->fptr) FatalError(XMLMOD"logfile (%s) open error (%s)\n", d->file, strerror(errno));
setvbuf(d->fptr,(char *)NULL, _IOLBF, (size_t)0);
}
else if(d->protocol != NULL)
{
if(d->host == NULL) FatalError(XMLMOD" can not use the protocol argument without a host argument\n");
}
else FatalError(XMLMOD"Invalid configuration options");
#ifdef ENABLE_SSL
if(d->protocol != NULL)
{
if((!strcasecmp(d->protocol, "https")) && (d->client_cert_filename == NULL))
FatalError(XMLMOD": must specify a certificate ([cert] parameter) when using https (SSL)\n");
if(!strcasecmp(d->protocol, "https") && d->client_key_filename == NULL)
FatalError(XMLMOD": must specify a private key ([key] parameter) when using https (SSL)\n");
if(!strcasecmp(d->protocol, "https") && d->collector_name == NULL)
FatalError(XMLMOD": must specify a server ([server] parameter) when using https (SSL)\n");
if(!strcasecmp(d->protocol, "https") && d->issuer_cert == NULL)
FatalError(XMLMOD": must specify a CA certificate ([ca] parameter) when using https (SSL)\n");
if((!strcasecmp(d->protocol, "https") || !strcasecmp(d->protocol, "http"))
&& d->file == NULL)
FatalError(XMLMOD": must specify a remote script ([file] parameter) with http or https\n");
}
#endif
return d;
}
/*
* Function: LogXml(Packet *, char * msg, void * data)
*
* Purpose: Generate the XML for a given packet and msg
*
* Arguments: p => pointer to the current packet data struct
* msg => pointer to the signature message
* data => passed in by snort
*
* Returns: void function
*
*/
void LogXml(Packet *p, char *msg, void *arg)
{
XmlData *d = (XmlData *)arg;
#ifdef ENABLE_SNORT_TIMING
SNORT_TIME_MARK_START(packet_cnt);
#endif
/* if (logging to a file) */
if((d->host == NULL) && (!d->port) && (d->protocol == NULL))
d->root = snml(d, p, msg);
else
addtag(d->root, snml(d, p, msg));
d->count++;
if(d->count >= MAX_QUEUE)
{
send_data(d);
flush_data(d);
}
#ifdef ENABLE_SNORT_TIMING
/* #6 : Final Clean-up */
SNORT_TIME_MARK();
SNORT_TIME_MARK_END();
#endif
}
/*
* Function: send_data(XmlData * data)
*
* Purpose: Write data to a file or over the network
*
* Arguments: data => pointer to an XmlData struct
*
* Returns: void function
*
*/
void send_data(XmlData *d)
{
char * output;
char * ptr;
int indent = 0;
/* if d->root is empty there is nothing really to send */
if(d->root == NULL)
return;
/* Turn the data into a string */
output = (char *)malloc(MAX_ALERT_SIZE * (MAX_QUEUE + 2));
ptr = output;
/* Don't add the SNORTML header if logging to a file */
if(!( (d->host == NULL) || (!d->port) || (d->protocol == NULL) ))
{
strncpy(ptr, SNORTML_DECLARATION, strlen(SNORTML_DECLARATION) + 1);
strncat(ptr, SNORTML_DOCTYPE, strlen(SNORTML_DOCTYPE) + 1);
ptr += strlen(SNORTML_DOCTYPE) + strlen(SNORTML_DECLARATION);
}
else
indent = INDENT;
ptr = tag2string(ptr, MAX_ALERT_SIZE * (MAX_QUEUE + 1), d->root, indent);
strncat(ptr, "\n", 1);
/* Write the XML to a file or send it over the network */
if((d->host == NULL) || (!d->port) || (d->protocol == NULL))
{
fprintf(d->fptr, "%s", output);
/*fflush(d->fptr);*/
}
else
{
#ifdef ENABLE_SNORT_TIMING
/* #1 : Client Alert Processing Time => Make XML */
SNORT_TIME_MARK();
#endif
/* send it over the network */
send_data_network(d, output);
}
free(output);
}
#ifdef ENABLE_SSL
void init_snort_ssl_ctx(XmlData *d)
/* Initializes an TLSv1 context */
{
int err;
SSLeay_add_ssl_algorithms();
/* d->meth = SSLv2_client_method(); */
/* d->meth = SSLv3_client_method(); */
d->meth = TLSv1_client_method();
SSL_load_error_strings();
d->ctx = SSL_CTX_new (d->meth);
CHK_NULL(d->ctx, XMLMOD_SSL": could not get a SSL context");
SSL_CTX_set_verify(d->ctx, SSL_VERIFY_PEER, CertVerifyCB);
SSL_CTX_set_default_verify_paths(d->ctx);
if(! SSL_CTX_load_verify_locations(d->ctx, d->issuer_filename, NULL))
{
ErrorMessage(XMLMOD": Could not load the CA chain");
return;
}
SSL_CTX_set_client_CA_list(d->ctx,SSL_load_client_CA_file(d->issuer_filename));
/* inits Client Authentication parameters; sets the certificate and key */
err = SSL_CTX_use_certificate_file (d->ctx, d->client_cert_filename, SSL_FILETYPE_PEM);
CHK_NULL(err, XMLMOD_SSL": invalid client certificate specified in config");
err = SSL_CTX_use_PrivateKey_file(d->ctx, d->client_key_filename, SSL_FILETYPE_PEM);
CHK_NULL(err, XMLMOD_SSL": invalid client private key specified in config");
SSL_CTX_set_session_cache_mode(d->ctx, SSL_SESS_CACHE_CLIENT);
return;
end:
X509_free(d->issuer_cert);
SSL_CTX_free (d->ctx);
exit(-1);
}
int CertVerifyCB (int ok, X509_STORE_CTX *ctx)
{
int errnum;
errnum = X509_STORE_CTX_get_error(ctx);
if(errnum != X509_V_OK)
ErrorMessage(XMLMOD": Authentication Error: CB : #%d : %s\n", errnum, X509_verify_cert_error_string(errnum));
return 1;
}
EVP_PKEY * load_key(char *key_fname)
/* Loads a PEM encoded RSA Private key from disk into memory */
{
BIO *in;
EVP_PKEY *x=NULL;
in=BIO_new(BIO_s_file_internal());
if((in == NULL))
goto error;
if(!BIO_read_filename(in, key_fname))
goto error;
PEM_read_bio_PrivateKey(in,&x,NULL,NULL);
error:
BIO_free(in);
return(x);
}
X509 * load_crt(char *ca_fname)
/* Loads a PEM encoded .CRT file from disk into memory */
{
BIO *in;
X509 *x=NULL;
in=BIO_new(BIO_s_file_internal());
if((in == NULL))
goto error;
if(!BIO_read_filename(in, ca_fname))
goto error;
PEM_read_bio_X509(in,&x,NULL,NULL);
error:
BIO_free(in);
return(x);
}
int VerifyServerCertificate(X509 *current, char *valid_server, X509 *issuer)
/* Validates a certificate based on an issuer certificate.
By the time this routine is called SSLeay has ensure us that
the 'current' certificate is signed by _our_ CA. Therefore,
we know that the server response at least came from inside our
community of users. The question now is whether:
1. The integrity of the certificate is intact
2. (TODO) The certificate has not expired or being used before
it is valid
3. (TODO) Some notion of a CRL
4. The server/user is a valid entity with which to communicate.
*/
{
char *ascii_cert = NULL;
int status = X509_V_OK;
EVP_PKEY *issuer_pkey = NULL;
/* Get the public key of the issuer (CA) */
if((issuer_pkey = X509_get_pubkey(issuer)) == NULL)
status = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
else
/* Use the Issuer public key to validate the integrity
of the server's certificate */
if(X509_verify(current, issuer_pkey) <= 0)
status = X509_V_ERR_CERT_SIGNATURE_FAILURE;
else
{
ascii_cert = X509_NAME_oneline (X509_get_subject_name (current),0,0);
if(strcmp(ascii_cert, valid_server) != 0)
status = X509_V_ERR_APPLICATION_VERIFICATION;
#ifdef DEBUG
printf("Comparing to the expected server'%s' ?= to '%s'\n",
valid_server, ascii_cert);
#endif
}
EVP_PKEY_free(issuer_pkey);
free(ascii_cert);
return status;
}
#endif
void BrokenNetConnection(int signal)
{
ErrorMessage(XMLMOD" : Remote connection terminated during logging. Alert dropped!\n");
}
void send_data_network(XmlData *d, char *output)
/* Sends the XML-formatted Snort output onto the wire: TCP socket,
HTTP, HTTPS
*/
{
#define POST_header_MAX 500
/* socket data structures */
struct sockaddr_in remote;
int err;
char POST_header[POST_header_MAX],
*report = NULL;
#ifdef ENABLE_SSL
/* int sent; */
/* SSL connection data structures */
SSL *ssl = NULL; /* particular ssl connection */
X509 *server_cert; /* X.509 certificate of server */
/* SSL temporary */
#ifdef DEBUG
char *ascii_cert_subject,
*ascii_cert_issuer; /* ASCII text of X.509 certificate */
#endif
SSLServerResponse *response = NULL; /* response codes of the mod_snort server */
int success_ssl_connect = 0;
#endif
/* POST temporary variables */
char rbuf[4096]; /* raw HTTP server response */
char content_line[25]; /* HTTP hdr: Content-Length: */
char *script = NULL; /* remote script to be executed */
/* Catch all the empty alerts triggered by abnormal Snort termination */
if(strstr(output, EMPTY_ALERT))
return;
++packet_cnt;
/* Open an socket connection */
d->sk = socket(AF_INET,SOCK_STREAM,0);
if(d->sk < 0)
{
ErrorMessage(XMLMOD" #%u : could not open connection to %s:%d."
"(socket - error #%d)\n",
packet_cnt, d->host, d->port, errno);
#ifdef ENABLE_SSL
LogSSLMessage(d->ssl_trace, "Could not open connection (socket() fail)",
"<not stored>", "<not stored>", packet_cnt, d->protocol, d->host, d->port, script);
#endif
return;
}
remote.sin_family=AF_INET;
bcopy( d->host_ipaddr->h_addr,(char*)&remote.sin_addr, d->host_ipaddr->h_length);
remote.sin_port= htons((unsigned short)d->port);
err = connect(d->sk,(struct sockaddr *)&remote,sizeof(remote));
if(err != 0)
{
if(errno == 111)
ErrorMessage(XMLMOD" #%u: Connection refused. No server found at %s:%d\n",
packet_cnt, d->host, d->port);
else
ErrorMessage(XMLMOD" #%u : could not open connection to %s:%d."
"(connect - error #%d)\n",
packet_cnt, d->host, d->port, errno);
#ifdef ENABLE_SSL
if(errno == 111)
LogSSLMessage(d->ssl_trace, "Connection refused (connect() fail)",
"<not stored>", "<not stored>", packet_cnt, d->protocol, d->host, d->port, script);
else
LogSSLMessage(d->ssl_trace, "Could not open connection (connect() fail)",
"<not stored>", "<not stored>", packet_cnt, d->protocol, d->host, d->port, script);
#endif
close(d->sk);
return;
}
#ifdef ENABLE_SSL
/* Configure the socket to do SSL if neccessary */
if(!strcasecmp(d->protocol, "https"))
{
/* Allocate a new SSL connection */
ssl = SSL_new (d->ctx);
CHK_NULL(ssl, XMLMOD_SSL": Could not alloc an SSL structure\n");
SSL_set_fd (ssl, d->sk); /* associate a file-desc with SSL */
#ifdef ENABLE_SESSION_RESUME
/* Re-use (if had one) the previous session whereby preventing _very_ expensive
* crypto operations */
if(d->session)
if(!SSL_set_session(ssl, d->session))
{
/* had an error, most likely the cache has expired. So lets flag
* the d->session as NULL so that the newly negotiated session
* is saved
*/
printf("Session Dropped from cache already\n");
d->session = NULL;
}
#endif
err = SSL_connect (ssl); /* connect() */
CHK_SSL(err, XMLMOD_SSL": Could not open SSL connection (SSL_connect())");
#ifdef ENABLE_SESSION_RESUME
/* If this is the first SSL_connect()/session, save the session */
if(!d->session)
d->session = SSL_get_session(ssl);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -