#include #include #include "pfparser.h" #include "helpers.h" #include "geo.h" int pfdata_parse(char* message, pf_data* result) { /*printf("pfparse: '%s'\n", message);*/ char* token; int field = 0; /* Parse the first 9 fields They are: ,,,,,,,, We only collect rule-number, real-interface, reason, action, direction, ip-version */ while ( (token = strsep(&message, ",")) != NULL) { /*printf("%02d: %s\n", field, token);*/ switch (field) { case 0: /* Rule number*/ { /*language limitation, the `char*` label (or `unsigned`) is not supported after a switch case TODO look up the underlying reason again*/ char* rnend; long int rulenum = strtol(token, &rnend, 10); if(rnend == NULL) return 1; result->rulenum = (int)rulenum; } /*if(result->rulenum == NULL) return 1;*/ break; case 4: /*iface*/ if(strlen(token) > IFACE_LEN) return 1; /*oddly log interface name, avoid buf overflow*/ memcpy(result->iface, token, strlen(token)); break; case 5: /*reason*/ result->reason = strcmp(token, "match") ? pf_hit_other : pf_hit_match; /*TODO error on unexpected*/ break; case 6: /*action*/ result->action = strcmp(token, "block") == 0 ? pf_hit_block : pf_hit_pass; /*XXX*/ break; case 7: /*direction*/ result->direction = strcmp(token, "in") ? pf_dir_in : pf_dir_out; /*XXX*/ break; case 8: /*ip-version*/ { char* ipvend; long int ip_ver = strtol(token, &ipvend, 10); if(ipvend == NULL) return 1; result->ipversion = (int)ip_ver; } break; } if(field == 8) { break; } field++; } if(result->ipversion == 4) { /*parse ipv4 fields*/ field = 0; while ( (token = strsep(&message, ",")) != NULL) { /*printf("%02d: %s\n", field, token);*/ switch (field) { case 0: /*TOS, hex as a string field starting with "0x" or empty*/ { char* rnend; int tos = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->ipv4_data.tos = tos; } break; case 1: /*"Explicit Congestion Notification" - or empty, we will ignore*/ break; case 2: /*TTL, int*/ { char* rnend; int ttl = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->ipv4_data.ttl = ttl; } break; case 3: /*packet ID, int (seemingly useless?)*/ break; case 4: /*fragment offset, int (???)*/ break; case 5: /*flags ("none" or some string, DF or MF - see https://en.wikipedia.org/wiki/IPv4#Flags)*/ break; case 6: /*protocol id, int*/ { char* rnend; int proto_id = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->ipv4_data.protocol = proto_id; } break; case 7: /*protocol name, string*/ break; } if(field == 7) { break; } field++; } } else if(result->ipversion == 6) { /*parse ipv6 fields*/ field = 0; while ( (token = strsep(&message, ",")) != NULL) { /*printf("%02d: %s\n", field, token);*/ switch (field) { case 0: /*class, hex as a string field starting with "0x"*/ break; case 1: /*flow label, "data" ???*/ break; case 2: /*hop-limit, int (like ttl)*/ { char* rnend; int ttl = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->ipv6_data.hoplimit = ttl; } break; case 3: /*protocol name, string*/ break; case 4: /*protocol id, int*/ { char* rnend; int proto_id = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->ipv6_data.protocol = proto_id; } break; } if(field == 4) { break; } field++; } } else { return 1; /*unknown ip version*/ } /*Parse */ /*parse ipv6 fields*/ field = 0; while ( (token = strsep(&message, ",")) != NULL) { /*printf("%02d: %s\n", field, token);*/ switch (field) { case 0: /*packet length, int*/ { char* rnend; int pack_len = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->packet_length = pack_len; } break; case 1: /*source addr, string (ipv4 OR ipv6!)*/ if(strlen(token) > IP_STR_LEN) return 1; /*too long ip string*/ memcpy(result->src_addr, token, strlen(token)); break; case 2: /*dest addr, string (ipv4 OR ipv6!)*/ if(strlen(token) > IP_STR_LEN) return 1; /*too long ip string*/ memcpy(result->dest_addr, token, strlen(token)); break; } if(field == 2) { break; } field++; } /*Parse optional one of | | | ICMP and CARP are ignored*/ if((result->ipversion == 4 && result->ipv4_data.protocol == 6) || (result->ipversion == 6 && result->ipv6_data.protocol == 6)) {/* tcp */ /*,,,,,,,,*/ /*printf("rest: %s\n", message);*/ /*parse ipv6 fields*/ field = 0; while ( (token = strsep(&message, ",")) != NULL) { /*printf("%02d: %s\n", field, token);*/ switch (field) { case 0: /*src port, int*/ { char* rnend; int num = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->tcp_data.srcport = num; } break; case 1: /*dest port, int*/ { char* rnend; int num = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->tcp_data.destport = num; } break; case 2: /*packet length, int*/ { char* rnend; int num = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->tcp_data.length = num; } break; } if(field == 8) { break; } field++; } } else if((result->ipversion == 4 && result->ipv4_data.protocol == 11) || (result->ipversion == 6 && result->ipv6_data.protocol == 11)) {/* udp */ /*,,*/ field = 0; while ( (token = strsep(&message, ",")) != NULL) { /*printf("%02d: %s\n", field, token);*/ switch (field) { case 0: /*src port, int*/ { char* rnend; int num = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->udp_data.srcport = num; } break; case 1: /*dest port, int*/ { char* rnend; int num = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->udp_data.destport = num; } break; case 2: /*packet length, int*/ { char* rnend; int num = strtol(token, &rnend, 0); if(rnend == NULL) return 1; result->udp_data.length = num; } break; } if(field == 2) { break; } field++; } } else if(result->ipversion == 4 && result->ipv4_data.protocol == 1){/* icmp-v4 */ } else if(result->ipversion == 6 && result->ipv6_data.protocol == 58){/* icmp-v6 */ } return 0; } void pfdata_print(pf_data* data) { printf("Action: %s\n", pfhastr[data->action]); printf("IP Data:\n\tInterface: %s\n\tIP version: %d\n", data->iface, data->ipversion); if(data->ipversion == 4) { printf("IPV4 Data:\n\tTTL: %d\n\tProtocol ID: %d\n", data->ipv4_data.ttl, data->ipv4_data.protocol); } else if(data->ipversion == 6) { printf("IPV6 Data:\n\tHop Limit: %d\n\tProtocol ID: %d\n", data->ipv6_data.hoplimit, data->ipv6_data.protocol); } printf("Endpoints:\n\tsrc: %s\n\tdest: %s\n", data->src_addr, data->dest_addr); if (data->ipversion == 4) { if (data->ipv4_data.protocol == 6) { printf("Protocol: tcp4\n\tsrcport: %d\n\tdestport: %d\n\tsize: %d\n", data->tcp_data.srcport, data->tcp_data.destport, data->tcp_data.length); } else if (data->ipv4_data.protocol == 11) { printf("Protocol: udp4\n\tsrcport: %d\n\tdestport: %d\n\tsize: %d\n", data->udp_data.srcport, data->udp_data.destport, data->udp_data.length); } } else if (data->ipversion == 6) { if (data->ipv6_data.protocol == 6) { printf("Protocol: tcp6\n\tsrcport: %d\n\tdestport: %d\n\tsize: %d\n", data->tcp_data.srcport, data->tcp_data.destport, data->tcp_data.length); } else if (data->ipv6_data.protocol == 11) { printf("Protocol: udp6\n\tsrcport: %d\n\tdestport: %d\n\tsize: %d\n", data->udp_data.srcport, data->udp_data.destport, data->udp_data.length); } } } void add_intfield(json_object* obj, char* name, int value) { json_object *ipversion = json_object_new_int(value); json_object_object_add(obj, name, ipversion); } void add_strfield(json_object* obj, char* name, char* value) { json_object *ipversion = json_object_new_string(value); json_object_object_add(obj, name, ipversion); } void add_doublefield(json_object* obj, char* name, double value) { json_object *number = json_object_new_double(value); json_object_object_add(obj, name, number); } const char* null_unknown(const char* p){ return p ? p : "unknown"; } int pfdata_to_json(pf_data* data, json_object* obj) { /* Populate the passed json_object obj with data from from pf_data data. */ add_strfield(obj, "interface", data->iface); add_intfield(obj, "ip_version", data->ipversion); add_strfield(obj, "action", (char*)(pfhastr[data->action])); add_strfield(obj, "direction", (char*)(pfdirstr[data->direction])); if(data->ipversion == 4) { add_intfield(obj, "ttl", data->ipv4_data.ttl); add_intfield(obj, "protocol_id", data->ipv4_data.protocol); } else if(data->ipversion == 6) { add_intfield(obj, "ttl", data->ipv6_data.hoplimit); add_intfield(obj, "protocol_id", data->ipv6_data.protocol); } add_strfield(obj, "src_addr", data->src_addr); add_strfield(obj, "dest_addr", data->dest_addr); if (data->ipversion == 4) { if (data->ipv4_data.protocol == 6) { add_intfield(obj, "src_port", data->tcp_data.srcport); add_intfield(obj, "dest_port", data->tcp_data.destport); add_intfield(obj, "length", data->tcp_data.length); } else if (data->ipv4_data.protocol == 11) { add_intfield(obj, "src_port", data->udp_data.srcport); add_intfield(obj, "dest_port", data->udp_data.destport); add_intfield(obj, "length", data->udp_data.length); } } else if (data->ipversion == 6) { if (data->ipv6_data.protocol == 6) { add_intfield(obj, "src_port", data->tcp_data.srcport); add_intfield(obj, "dest_port", data->tcp_data.destport); add_intfield(obj, "length", data->tcp_data.length); } else if (data->ipv6_data.protocol == 11) { add_intfield(obj, "src_port", data->udp_data.srcport); add_intfield(obj, "dest_port", data->udp_data.destport); add_intfield(obj, "length", data->udp_data.length); } } return 0; }