From c1d99a1f8604c2a2cf32d878ade2b31554135482 Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 25 May 2018 17:12:09 -0700 Subject: [PATCH] Refactoring --- src/Makefile | 2 +- src/main.c | 177 +++++++----------------------------------------- src/pfparser.c | 2 +- src/pfparser.h | 6 +- src/sysparser.c | 130 +++++++++++++++++++++++++++++++++++ src/sysparser.h | 26 +++++++ 6 files changed, 186 insertions(+), 157 deletions(-) create mode 100644 src/sysparser.c create mode 100644 src/sysparser.h diff --git a/src/Makefile b/src/Makefile index 253625e..3cc90c4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,7 @@ CC=gcc -Wall CFLAGS=-g -I. CFLAGS_STATIC=$(CCLAGS) --static DEPS= -OBJ=main.o pfparser.o +OBJ=main.o pfparser.o sysparser.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/src/main.c b/src/main.c index 85bf776..7457f4a 100644 --- a/src/main.c +++ b/src/main.c @@ -11,165 +11,25 @@ #include #include #include "helpers.h" -#include "pfparser.h" +// #include "pfparser.h" +#include "sysparser.h" #include /*UDP server-related mostly lifted from https://cs.nyu.edu/~mwalfish/classes/16sp/classnotes/handout01.pdf*/ -#define DF_MONTH_LEN 9 - -/*TODO numeric indicator for month?*/ -struct Datefields { - char month[DF_MONTH_LEN]; - int day; - int hour; - int minute; - int second; -}; - -/*TODO check max app name length*/ -#define MSG_APP_LEN 64 - -struct Message { - int priority; - char application[MSG_APP_LEN]; - struct Datefields date; - pf_message data; -}; - - void panic(const char* s) { perror(s); exit(1); } -int parse_priority(char* message, int* priority, int* position) { - /* - Given a string that begins with a message something like: <123>foo - Parse out the number (123) and place it in the passed `priority` int pointer - The position after the final `>` will be placed in the passed `position` int pointer - Returns 0 on success or something else on failure - */ - /*Must have >3 chars to form priority*/ - if (strlen(message) < 3) return 1; - /*Must start with <*/ - if (message[0] != '<') return 1; - char digits[4]; - memset(&digits, '\0', sizeof(digits)); - int num_digits = 0; - int pos = 1; - /*bool found_priority_end = false; // TODO*/ - while (pos < 4) { - if(!isdigit(message[pos])) return 1; /*priority must be numeric*/ - digits[num_digits] = message[pos]; - num_digits++; - pos++; - if (message[pos] == '>') { - break; - } - } - /*TODO if escape the loop because pos >= 4, we never found '>'*/ - if (num_digits == 0) return 1; /*empty priority <> ?*/ - *priority = atoi(digits); - *position = pos; - return 0; -} - - -int parse_datefield(char* message, struct Datefields* date, int* position) { - /* - Given a message+position pointers, where message + position in a string like: - May 10 03:09:59 filterlog: 5,,,.... - Parse out the date and place the fields in the passed datefields struct pointer - Position will be advanced to the character after the parsed data - */ - /*char month[8]; - memset(&month, '\0', sizeof(month)); makes valgrind happy as the above char contains uninitialized memory*/ - int date_length; - if(sscanf(message + *position, "%"STR(DF_MONTH_LEN)"s %d %d:%d:%d%n", - date->month, &(date->day), &(date->hour), &(date->minute), &(date->second), &date_length) != 5) { - return 1; /*Failed to parse all desired fields*/ - } - *position += date_length; - return 0; -} - - -int parse_application(char* message, char* application, int* position) { - int app_length; - if(sscanf(message + *position, "%"STR(MSG_APP_LEN)"s%n", application, &app_length) != 1) { /*%n not counted in returned field count*/ - return 1; /*Failed to parse all desired fields*/ - } - if(strlen(application) < 2) return 1; /*Expect at least chars*/ - application[app_length-1] = '\0'; /*Remove the trailing :*/ - *position += app_length; - return 0; -} - - -int parse_message(struct Message* result, char* message) { - /* - parse a message like: - <134>May 10 03:09:59 filterlog: 5,,,1000000103,cpsw0,match,block,in,4,0x20,,239,27547,0,none,6,tcp,40,185.216.140.37,24.4.129.164,57159,11111,0,S,3919167832,,1024,, - Format: - VERSION ISOTIMESTAMP HOSTNAME APPLICATION PID MESSAGEID STRUCTURED-DATA MSG - Assumes null termed string - */ - int priority = 0; - int position = 0; - if(parse_priority(message, &priority, &position) != 0) return 1; - result->priority = priority; - position++; /*Now sits on the first character of the ISOTIMESTAMP*/ - - /*Parse ISOTIMESTAMP - Note: does not parse a full iso timestamp, only the format above*/ - struct Datefields date; - if(parse_datefield(message, &date, &position) != 0) { - return 1; - } - result->date = date; - position++; /*position now at beginning of HOSTNAME field*/ - - /*Parse APPLICATION - filterlog: 5,,,1000000103,cpsw0,match....*/ - char application[MSG_APP_LEN]; - if(parse_application(message, application, &position) != 0) return 1; - memcpy(result->application, application, sizeof(application)); - position += 1; /*pass over the space*/ - - /*printf("remaining: '%s'\n", message + position);*/ - - /*trim original message to only the CSV portion*/ - int msglen = strlen(message); - int datalen = msglen - position; - memmove(message, &message[position], datalen); - /*zero the rest of the message*/ - memset(&message[datalen], 0, msglen - datalen); - - /*pf_message result_msg;*/ - if(pfparse_message(message, &(result->data)) != 0) return 1; - - - /*char msg_remaining[4096]; - memset(&msg_remaining, '\0', sizeof(msg_remaining)); - memcpy(msg_remaining, &message[position], strlen(message) - position); - printf("'%s'\n", msg_remaining); - or - memmove(message, &message[position], strlen(message) - position); - printf("'%s'\n", message);*/ - - return 0; -} - - int running = 1; int sock_fd; -void handler(int signum) { - printf("Exiting on signal %s\n", strsignal(signum)); +void sig_handler(int signum) { + printf("\nExiting on signal %s\n", strsignal(signum)); running = 0; /* shut down the loop */ shutdown(sock_fd, SHUT_RDWR); /* break the listener socket */ close(sock_fd); @@ -182,8 +42,8 @@ int main(int argc, char** argv) { exit(1); } - signal(SIGTERM, handler); - signal(SIGINT, handler); + signal(SIGTERM, sig_handler); + signal(SIGINT, sig_handler); /*Parse port number to integer*/ char* portend; @@ -232,16 +92,29 @@ int main(int argc, char** argv) { /*TODO should we check that msg[size_recvd] == \0 ? printf("From host %s src port %d got message %.*s\n", inet_ntoa(my_peer_addr.sin_addr), ntohs(my_peer_addr.sin_port), size_recvd, msg);*/ - struct Message result; + struct SysMessage result; memset(&result, 0, sizeof(result)); /* Doing this or setting result above to `= {};` seems to make valgrind happy */ /*printf("\nsize: %lu\n\n", sizeof(result)); // curious how big the struct gets // printf("msg[size_recvd] is: %d", msg[size_recvd]);*/ msg[size_recvd] = '\0'; /*We receive 1 full string at a time*/ - if(parse_message(&result, msg) != 1) { - printf("message is valid:\n\tpriority: %d\n\tapplication: %s\n\tDate: %s %d %02d:%02d:%02d\n" - "\tInterface: %s\n\tIP version: %d\n", - result.priority, result.application, result.date.month, result.date.day, result.date.hour, - result.date.minute, result.date.second, result.data.iface, result.data.ipversion); + + if(sysmsg_parse(&result, msg) != 0) { + printf("Failed to parse message: %s", msg); + } else { + printf("syslogmessage is valid:\n\tpriority: %d\n\tapplication: %s\n\tDate: %s %d %02d:%02d:%02d\n\t\n", + result.priority, result.application, result.date.month, result.date.day, result.date.hour, + result.date.minute, result.date.second); + + pf_data fwdata; + memset(&fwdata, 0, sizeof(fwdata)); + + if(pfparse_message(msg, &fwdata) != 0) { + printf("Failed to parse pfsense data: %s", msg); + } else { + printf("IP Data:\n\tInterface: %s\n\tIP version: %d\n", + fwdata.iface, fwdata.ipversion); + } + } } diff --git a/src/pfparser.c b/src/pfparser.c index c092750..b9da973 100644 --- a/src/pfparser.c +++ b/src/pfparser.c @@ -5,7 +5,7 @@ -int pfparse_message(char* message, pf_message* result) { +int pfparse_message(char* message, pf_data* result) { printf("pfparse: '%s'\n", message); char* token; diff --git a/src/pfparser.h b/src/pfparser.h index 23a948e..2cce218 100644 --- a/src/pfparser.h +++ b/src/pfparser.h @@ -17,15 +17,15 @@ typedef enum pf_direction { pf_dir_out } pf_direction; -typedef struct pf_message { +typedef struct pf_data { int rulenum; char iface[IFACE_LEN]; pf_hit_reason reason; pf_hit_action action; pf_direction direction; int ipversion; -} pf_message; +} pf_data; -int pfparse_message(char* message, pf_message* result); +int pfparse_message(char* message, pf_data* result); diff --git a/src/sysparser.c b/src/sysparser.c new file mode 100644 index 0000000..0bb1fa6 --- /dev/null +++ b/src/sysparser.c @@ -0,0 +1,130 @@ +#include "sysparser.h" +#include +#include "helpers.h" +#include +#include +#include + + +int parse_priority(char* message, int* priority, int* position) { + /* + Given a string that begins with a message something like: <123>foo + Parse out the number (123) and place it in the passed `priority` int pointer + The position after the final `>` will be placed in the passed `position` int pointer + Returns 0 on success or something else on failure + */ + /*Must have >3 chars to form priority*/ + if (strlen(message) < 3) return 1; + /*Must start with <*/ + if (message[0] != '<') return 1; + char digits[4]; + memset(&digits, '\0', sizeof(digits)); + int num_digits = 0; + int pos = 1; + /*bool found_priority_end = false; // TODO*/ + while (pos < 4) { + if(!isdigit(message[pos])) return 1; /*priority must be numeric*/ + digits[num_digits] = message[pos]; + num_digits++; + pos++; + if (message[pos] == '>') { + break; + } + } + /*TODO if escape the loop because pos >= 4, we never found '>'*/ + if (num_digits == 0) return 1; /*empty priority <> ?*/ + *priority = atoi(digits); + *position = pos; + return 0; +} + + +int parse_datefield(char* message, struct Datefields* date, int* position) { + /* + Given a message+position pointers, where message + position in a string like: + May 10 03:09:59 filterlog: 5,,,.... + Parse out the date and place the fields in the passed datefields struct pointer + Position will be advanced to the character after the parsed data + */ + /*char month[8]; + memset(&month, '\0', sizeof(month)); makes valgrind happy as the above char contains uninitialized memory*/ + int date_length; + if(sscanf(message + *position, "%"STR(DF_MONTH_LEN)"s %d %d:%d:%d%n", + date->month, &(date->day), &(date->hour), &(date->minute), &(date->second), &date_length) != 5) { + return 1; /*Failed to parse all desired fields*/ + } + *position += date_length; + return 0; +} + + +int parse_application(char* message, char* application, int* position) { + int app_length; + if(sscanf(message + *position, "%"STR(MSG_APP_LEN)"s%n", application, &app_length) != 1) { /*%n not counted in returned field count*/ + return 1; /*Failed to parse all desired fields*/ + } + if(strlen(application) < 2) return 1; /*Expect at least chars*/ + application[app_length-1] = '\0'; /*Remove the trailing :*/ + *position += app_length; + return 0; +} + + +int sysmsg_parse(struct SysMessage* result, char* message) { + /* + parse a message like: + <134>May 10 03:09:59 filterlog: 5,,,1000000103,cpsw0,match,block,in,4,0x20,,239,27547,0,none,6,tcp,40,185.216.140.37,24.4.129.164,57159,11111,0,S,3919167832,,1024,, + Format: + VERSION ISOTIMESTAMP HOSTNAME APPLICATION PID MESSAGEID STRUCTURED-DATA MSG + Assumes null termed string + Param message will be transformed to the MSG field + */ + int priority = 0; + int position = 0; + if(parse_priority(message, &priority, &position) != 0) return 1; + result->priority = priority; + position++; /*Now sits on the first character of the ISOTIMESTAMP*/ + + /*Parse ISOTIMESTAMP + Note: does not parse a full iso timestamp, only the format above*/ + struct Datefields date; + if(parse_datefield(message, &date, &position) != 0) { + return 1; + } + result->date = date; + position++; /*position now at beginning of HOSTNAME field*/ + + /*Parse APPLICATION + filterlog: 5,,,1000000103,cpsw0,match....*/ + char application[MSG_APP_LEN]; + if(parse_application(message, application, &position) != 0) return 1; + memcpy(result->application, application, sizeof(application)); + position += 1; /*pass over the space*/ + + /*printf("remaining: '%s'\n", message + position);*/ + + /*trim original message to only the CSV portion*/ + int msglen = strlen(message); + int datalen = msglen - position; + memmove(message, &message[position], datalen); + /*zero the rest of the message*/ + memset(&message[datalen], 0, msglen - datalen); + + /*pf_message result_msg;*/ + // if(pfparse_message(message, &(result->data)) != 0) return 1; + + /* put message in result */ + // memcpy(&(result->message), message, strlen(message)); + // result->message = message + position; + + + /*char msg_remaining[4096]; + memset(&msg_remaining, '\0', sizeof(msg_remaining)); + memcpy(msg_remaining, &message[position], strlen(message) - position); + printf("'%s'\n", msg_remaining); + or + memmove(message, &message[position], strlen(message) - position); + printf("'%s'\n", message);*/ + + return 0; +} diff --git a/src/sysparser.h b/src/sysparser.h new file mode 100644 index 0000000..c3491c2 --- /dev/null +++ b/src/sysparser.h @@ -0,0 +1,26 @@ +#include "pfparser.h" + +#define DF_MONTH_LEN 9 + +/*TODO numeric indicator for month?*/ +struct Datefields { + char month[DF_MONTH_LEN]; + int day; + int hour; + int minute; + int second; +}; + +/*TODO check max app name length*/ +#define MSG_APP_LEN 64 + +struct SysMessage { + int priority; + char application[MSG_APP_LEN]; + struct Datefields date; + // char message; + // pf_message data; +}; + + +int sysmsg_parse(struct SysMessage* result, char* message);