X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2Fpvefw-logger.c;h=2bd869c4afa86f36e92b5d0bd1938c4c89affd97;hb=bf2fa11471823124b257321617924aa6811aecdf;hp=b7a2fb2983258e8cfc14d322151e0913e642e6bf;hpb=0b18ebe80ebaca7428dc11b13fe154104b121d50;p=pve-firewall.git diff --git a/src/pvefw-logger.c b/src/pvefw-logger.c index b7a2fb2..2bd869c 100644 --- a/src/pvefw-logger.c +++ b/src/pvefw-logger.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include #include @@ -175,8 +177,17 @@ queue_log_entry(struct log_entry *le) } -#define LEPRINTF(format, ...) { if (le->len < LE_MAX) le->len += snprintf(le->buf + le->len, LE_MAX - le->len, format, ##__VA_ARGS__); } -#define LEPRINTTIME(sec) { time_t tmp_sec = sec; if (le->len < (LE_MAX - 30)) le->len += strftime(le->buf + le->len, LE_MAX - le->len, "%d/%b/%Y:%H:%M:%S %z ", localtime(&tmp_sec)); } +#define LEPRINTF(format, ...) \ + do { \ + if (le->len < LE_MAX) \ + le->len += snprintf(le->buf + le->len, LE_MAX - le->len, format, ##__VA_ARGS__); \ + } while (0) +#define LEPRINTTIME(sec) \ + do { \ + time_t tmp_sec = sec; \ + if (le->len < (LE_MAX - 30)) \ + le->len += strftime(le->buf + le->len, LE_MAX - le->len, "%d/%b/%Y:%H:%M:%S %z ", localtime(&tmp_sec)); \ + } while (0) static void log_status_message(guint loglevel, const char *fmt, ...) @@ -309,6 +320,37 @@ print_sctp(struct log_entry *le, struct sctphdr *h, int payload_len) return 0; } +static int +print_ipproto(struct log_entry *le, char * nexthdr, int payload_len, u_int8_t proto) +{ + switch (proto) { + case IPPROTO_TCP: + print_tcp(le, (struct tcphdr *)nexthdr, payload_len); + break; + case IPPROTO_UDP: + print_udp(le, (struct udphdr *)nexthdr, payload_len); + break; + case IPPROTO_ICMP: + print_icmp(le, (struct icmphdr *)nexthdr, payload_len); + break; + case IPPROTO_SCTP: + print_sctp(le, (struct sctphdr *)nexthdr, payload_len); + break; + case IPPROTO_AH: + LEPRINTF("PROTO=AH "); + break; + case IPPROTO_ESP: + LEPRINTF("PROTO=ESP "); + break; + case IPPROTO_IGMP: + LEPRINTF("PROTO=IGMP "); + break; + default: + return -1; + } + return 0; +} + static int print_iphdr(struct log_entry *le, char * payload, int payload_len) { @@ -346,41 +388,269 @@ print_iphdr(struct log_entry *le, char * payload, int payload_len) void *nexthdr = (u_int32_t *)h + h->ihl; payload_len -= h->ihl * 4; - switch (h->protocol) { - case IPPROTO_TCP: - print_tcp(le, (struct tcphdr *)nexthdr, payload_len); + if (print_ipproto(le, nexthdr, payload_len, h->protocol) < 0) { + LEPRINTF("PROTO=%u ", h->protocol); + } + + return 0; +} + +static int +print_routing(struct log_entry *le, struct ip6_rthdr *rthdr, int payload_len) +{ + char tmp[INET6_ADDRSTRLEN]; + LEPRINTF("TYPE=%u SEGMENTS=%u", rthdr->ip6r_type, rthdr->ip6r_segleft); + + if (payload_len < sizeof(*rthdr) || payload_len < rthdr->ip6r_len*8) { + LEPRINTF("LEN=%d ", payload_len); + LEPRINTF("INVALID=LEN "); + return -1; + } + + if (rthdr->ip6r_type == 0) { + /* Route via waypoints (deprecated), this contains a list of waypoints + * to visit. (RFC2460 (4.4)) + */ + struct ip6_rthdr0 *h = (struct ip6_rthdr0*)rthdr; + if (rthdr->ip6r_len*8 < sizeof(*h) + rthdr->ip6r_segleft * sizeof(struct in6_addr)) { + LEPRINTF("INVALID=SEGMENTS "); + return 0; + } + return 0; + } else if (rthdr->ip6r_type == 1) { + /* nimrod routing (RFC1992) */ + return 0; + } else if (rthdr->ip6r_type == 2) { + /* RFC3375 (6.4), the layout is like type-0 but with exactly 1 address */ + struct ip6_rthdr0 *h = (struct ip6_rthdr0*)rthdr; + if (rthdr->ip6r_len*8 < sizeof(*h) + sizeof(struct in6_addr)) { + LEPRINTF("LEN=%d ", payload_len); + LEPRINTF("INVALID=LEN "); + return -1; + } + inet_ntop(AF_INET6, &h->ip6r0_addr[0], tmp, sizeof(tmp)); + LEPRINTF("HOME=%s ", tmp); + return 0; + } + + return 0; +} + +static int +print_fragment(struct log_entry *le, struct ip6_frag *frag, int payload_len) +{ + u_int16_t offlg; + + if (payload_len < sizeof(*frag)) { + LEPRINTF("LEN=%d ", payload_len); + LEPRINTF("INVALID=LEN "); + return -1; + } + + offlg = ntohs(frag->ip6f_offlg); + LEPRINTF("FRAG=%d ID=%d ", (offlg&0x2FFF), ntohl(frag->ip6f_ident)); + if (offlg>>15) { + LEPRINTF("MF "); + } + return 0; +} + +static int +print_icmp6(struct log_entry *le, struct icmp6_hdr *h, int payload_len) +{ + struct nd_router_advert *ra; + struct nd_neighbor_advert *na; + struct nd_redirect *re; + char tmp[INET6_ADDRSTRLEN]; + + if (payload_len < sizeof(struct icmp6_hdr)) { + LEPRINTF("LEN=%d ", payload_len); + LEPRINTF("INVALID=LEN "); + return -1; + } + + LEPRINTF("TYPE=%u CODE=%u ", h->icmp6_type, h->icmp6_code); + + switch (h->icmp6_type) { + case ICMP6_ECHO_REQUEST: + case ICMP6_ECHO_REPLY: + LEPRINTF("ID=%u SEQ=%u ", ntohs(h->icmp6_id), ntohs(h->icmp6_seq)); break; - case IPPROTO_UDP: - print_udp(le, (struct udphdr *)nexthdr, payload_len); + + case ND_ROUTER_SOLICIT: + /* can be followed by options, otherwise nothing to print */ break; - case IPPROTO_ICMP: - print_icmp(le, (struct icmphdr *)nexthdr, payload_len); + + case ND_ROUTER_ADVERT: + ra = (struct nd_router_advert*)h; + LEPRINTF("HOPLIMIT=%d ", ra->nd_ra_curhoplimit); + /* nd_ra_flags_reserved is only 8 bit, so no swapping here as + * opposed to the neighbor advertisement flags (see below). + */ + LEPRINTF("RA=%02x LIFETIME=%d REACHABLE=%d RETRANSMIT=%d ", + ra->nd_ra_flags_reserved, + ntohs(ra->nd_ra_router_lifetime), + ntohl(ra->nd_ra_reachable), + ntohl(ra->nd_ra_retransmit)); + /* can be followed by options */ break; - case IPPROTO_SCTP: - print_sctp(le, (struct sctphdr *)nexthdr, payload_len); + + case ND_NEIGHBOR_SOLICIT: + /* can be followed by options */ break; - case IPPROTO_AH: - LEPRINTF("PROTO=AH "); + + case ND_NEIGHBOR_ADVERT: + na = (struct nd_neighbor_advert*)h; + LEPRINTF("NA=%08x ", ntohl(na->nd_na_flags_reserved)); + /* can be followed by options */ break; - case IPPROTO_ESP: - LEPRINTF("PROTO=ESP "); + + case ND_REDIRECT: + re = (struct nd_redirect*)h; + inet_ntop(AF_INET6, &re->nd_rd_target, tmp, sizeof(tmp)); + LEPRINTF("TARGET=%s ", tmp); + inet_ntop(AF_INET6, &re->nd_rd_dst, tmp, sizeof(tmp)); + LEPRINTF("GATEWAY=%s ", tmp); + /* can be followed by options */ break; - case IPPROTO_IGMP: - LEPRINTF("PROTO=IGMP "); + + case ICMP6_DST_UNREACH: + /* CODE shows the type, no extra parameters available in ipv6 */ + break; + + case ICMP6_PACKET_TOO_BIG: + LEPRINTF("MTU=%u ", ntohl(h->icmp6_mtu)); + break; + + case ICMP6_TIME_EXCEEDED: + /* CODE shows the type (0 = hop limit, 1 = reassembly timed out) */ + break; + + case ICMP6_PARAM_PROB: + switch (ntohl(h->icmp6_pptr)) { + case ICMP6_PARAMPROB_HEADER: + LEPRINTF("PARAMETER=HEADER "); /* erroneous header */ + break; + case ICMP6_PARAMPROB_NEXTHEADER: + LEPRINTF("PARAMETER=NEXTHEADER "); /* bad next-header field */ + break; + case ICMP6_PARAMPROB_OPTION: + LEPRINTF("PARAMETER=OPTION "); /* bad ipv6 option (hop/dst header?) */ + break; + default: + LEPRINTF("PARAMETER=%u ", ntohl(h->icmp6_pptr)); /* unknown */ + break; + } break; - default: - LEPRINTF("PROTO=%u ", h->protocol); } return 0; } +static int +check_ip6ext(struct log_entry *le, struct ip6_ext *exthdr, int payload_len) +{ + if (payload_len < sizeof(*exthdr) || + payload_len < exthdr->ip6e_len) + { + LEPRINTF("LEN=%d ", payload_len); + LEPRINTF("INVALID=LEN "); + return -1; + } + return 0; +} + +static int +print_nexthdr(struct log_entry *le, char *hdr, int payload_len, u_int8_t proto) +{ + while (1) { + if (print_ipproto(le, hdr, payload_len, proto) == 0) + return 0; + + struct ip6_ext *exthdr = (struct ip6_ext*)hdr; + + switch (proto) { + /* protocols (these return) */ + case IPPROTO_ICMPV6: + LEPRINTF("PROTO=ICMPV6 "); + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + if (print_icmp6(le, (struct icmp6_hdr*)(hdr + exthdr->ip6e_len), + payload_len - exthdr->ip6e_len) < 0) + { + return -1; + } + return 0; + + /* extension headers (these break to keep iterating) */ + case IPPROTO_ROUTING: + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + if (print_routing(le, (struct ip6_rthdr*)hdr, payload_len) < 0) + return -1; + break; + case IPPROTO_FRAGMENT: + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + if (print_fragment(le, (struct ip6_frag*)hdr, payload_len) < 0) + return -1; + break; + case IPPROTO_HOPOPTS: + LEPRINTF("NEXTHDR=HOPOPTS "); + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + /* do we want to print these? */ + break; + case IPPROTO_DSTOPTS: + LEPRINTF("NEXTHDR=DSTOPTS "); + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + /* do we want to print these? */ + break; + case IPPROTO_MH: + LEPRINTF("NEXTHDR=MH "); + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + break; + + /* unknown protocol */ + default: + LEPRINTF("PROTO=%u ", proto); + return 0; /* bail */ + } + /* next header: */ + if (check_ip6ext(le, exthdr, payload_len) < 0) + return -1; + hdr += exthdr->ip6e_len; + payload_len -= exthdr->ip6e_len; + } +} + static int print_ip6hdr(struct log_entry *le, char * payload, int payload_len) { - LEPRINTF("IPV6 logging not implemented "); + if (payload_len < sizeof(struct ip6_hdr)) { + LEPRINTF("LEN=%d ", payload_len); + LEPRINTF("INVALID=LEN "); + return -1; + } - return 0; + struct ip6_hdr *h = (struct ip6_hdr*)payload; + + char tmp[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &h->ip6_src, tmp, sizeof(tmp)); + LEPRINTF("SRC=%s ", tmp); + inet_ntop(AF_INET6, &h->ip6_dst, tmp, sizeof(tmp)); + LEPRINTF("DST=%s ", tmp); + + LEPRINTF("LEN=%u ", ntohs(h->ip6_plen)); + + u_int32_t flow = ntohl(h->ip6_flow); + LEPRINTF("TC=%d FLOWLBL=%d ", (flow>>20)&0xFF, flow&0xFFFFF); + + LEPRINTF("HOPLIMIT=%d ", h->ip6_hlim); + + return print_nexthdr(le, (char *)(h+1), payload_len - sizeof(*h), h->ip6_nxt); } // ebtables -I FORWARD --nflog --nflog-group 0 @@ -483,9 +753,11 @@ static int print_pkt(struct log_entry *le, struct nflog_data *ldata, u_int8_t fa LEPRINTF("%s ", chain_name); struct timeval ts; - nflog_get_timestamp(ldata, &ts); - - LEPRINTTIME(ts.tv_sec); + if (nflog_get_timestamp(ldata, &ts) == 0) { + LEPRINTTIME(ts.tv_sec); + } else { + LEPRINTTIME(time(NULL)); + } if (prefix != NULL) { LEPRINTF("%s", prefix); @@ -653,7 +925,7 @@ main(int argc, char *argv[]) gboolean wrote_pidfile = FALSE; - openlog("pvepw-logger", LOG_CONS|LOG_PID, LOG_DAEMON); + openlog("pvefw-logger", LOG_CONS|LOG_PID, LOG_DAEMON); GOptionContext *context; @@ -712,7 +984,7 @@ main(int argc, char *argv[]) exit(-1); } - if (!nflog_bind_pf(logh, AF_INET) <= 0) { + if (nflog_bind_pf(logh, AF_INET) < 0) { fprintf(stderr, "nflog_bind_pf AF_INET failed\n"); exit(-1); } @@ -724,7 +996,7 @@ main(int argc, char *argv[]) } #endif - if (!nflog_bind_pf(logh, AF_BRIDGE) <= 0) { + if (nflog_bind_pf(logh, AF_BRIDGE) < 0) { fprintf(stderr, "nflog_bind_pf AF_BRIDGE failed\n"); exit(-1); }