From: Martin Mares Date: Sun, 6 Jan 2008 18:56:17 +0000 (+0100) Subject: The big cleanup. X-Git-Tag: v1.0~4 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=33a4449db98ab97cd650fed36536b6082ce75053;p=siplog.git The big cleanup. --- diff --git a/siplog.c b/siplog.c index 81d36a8..c458471 100644 --- a/siplog.c +++ b/siplog.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,12 @@ #include typedef unsigned char byte; +typedef unsigned int uns; + +static inline int is_white(int c) +{ + return (c == ' ' || c == '\t'); +} /*** Configuration ***/ @@ -27,12 +34,12 @@ static config_entry_t sip_cf_log = { /*** Unaligned access ***/ -static unsigned int get_u16(byte *p) +static uns get_u16(byte *p) { return (p[0] << 8) | p[1]; } -static unsigned int get_u32(byte *p) +static uns get_u32(byte *p) { return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; } @@ -41,7 +48,7 @@ static unsigned int get_u32(byte *p) static struct { char *name; - unsigned int id; + uns id; } keys[] = { { "raw.pkt", 0 }, { "raw.pktlen", 0 }, @@ -60,7 +67,7 @@ enum { static int init_keys(void) { - for (unsigned int i=0; i < sizeof(keys)/sizeof(keys[0]); i++) + for (uns i=0; i < sizeof(keys)/sizeof(keys[0]); i++) if (!(keys[i].id = keyh_getid(keys[i].name))) { ulogd_log(ULOGD_ERROR, "SIP: Unable to resolve key %s\n", keys[i].name); @@ -75,45 +82,93 @@ static int init_keys(void) #define KEY_TYPE(i) KEY_H(i).type #define KEY_OK(i,t) ((KEY_FLAGS(i) & ULOGD_RETF_VALID) && KEY_TYPE(i) == ULOGD_RET_##t) -/*** Logging ***/ - -static FILE *siplog; +/*** Representation of packets ***/ + +struct pkt { + time_t time_sec; // Arrival time + uns time_usec; + char time[64]; + byte *raw; // Raw packet + uns raw_len; + uns out_p; + byte *ip; // Inside IP + uns ip_len; + uns src_addr, dst_addr; + byte *udp; // Inside UDP + uns udp_len; + uns src_port, dst_port; + char *sip_rr; // Decoded SIP + struct hdr *sip_hdr; +}; struct hdr { struct hdr *next; char *name, *value; }; -static void sip_parse_obj(char *rr, struct hdr *headers) +/*** Logging ***/ + +static FILE *siplog; +static int verbose = 1; + +static void debug(char *fmt, ...) { + if (!verbose) + return; + va_list args; + va_start(args, fmt); + fputc('\t', siplog); + vfprintf(siplog, fmt, args); + fputc('\n', siplog); + va_end(args); +} + +static int error(struct pkt *pkt, char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fprintf(siplog, "%s ", pkt->time); + vfprintf(siplog, fmt, args); + fputc('\n', siplog); + va_end(args); + return 0; } -static void sip_parse_header(byte *pkt, unsigned int len) +static int parse_rr(struct pkt *pkt) { - char *p = (char*) pkt; - char *end = p + len; - struct hdr *headers = NULL; + char *rr = pkt->sip_rr; + if (!strncmp(rr, "SIP/", 4)) + { + // Reply + while (*rr && !is_white(*rr)) + rr++; + while (is_white(*rr)) + rr++; + } + else + { + // Request + } + return 1; +} -#if 0 - for (unsigned int i=0; iudp; + char *end = p + pkt->udp_len; + pkt->sip_hdr = NULL; // Parse the request/reply line first - char *rr = p; + pkt->sip_rr = p; while (p < end && *p != '\r' && *p != '\n') p++; if (p >= end) - { - fprintf(siplog, "\tTruncated 1st line\n"); - return; - } + return error(pkt, "Truncated 1st line"); if (*p == '\r') *p++ = 0; if (p < end && *p == '\n') *p++ = 0; - fprintf(siplog, "\t>>> %s\n", rr); + debug(">>> %s", pkt->sip_rr); // Slurp the other header lines for (;;) @@ -123,16 +178,13 @@ static void sip_parse_header(byte *pkt, unsigned int len) for (;;) { if (p >= end) - { - fprintf(siplog, "\tTruncated SIP headers\n"); - return; - } + return error(pkt, "Truncated SIP headers"); if (*p == '\r') p++; else if (*p == '\n') { p++; - if (p < end && (*p == ' ' || *p == '\t')) + if (p < end && is_white(*p)) ; else { @@ -145,95 +197,92 @@ static void sip_parse_header(byte *pkt, unsigned int len) } if (!start[0]) break; - // fprintf(siplog, "\tH: %s\n", start); // Got a line, parse it char *sep = strchr(start, ':'); if (!*sep) - { - fprintf(siplog, "\tMalformed header line\n"); + { + error(pkt, "Malformed header line"); continue; } *sep = 0; - for (char *p=sep; p>start && (p[-1] == ' ' || p[-1] == '\t');) + for (char *p=sep; p>start && is_white(p[-1]);) *--p = 0; - while (++sep < end && (*sep == ' ' || *sep == '\t')) + while (++sep < end && is_white(*sep)) *sep = 0; - fprintf(siplog, "\t%s: %s\n", start, sep); + debug("\t%s: %s", start, sep); struct hdr *h = alloca(sizeof(*h)); - h->next = headers; - headers = h; + h->next = pkt->sip_hdr; + pkt->sip_hdr = h; h->name = start; h->value = sep; } - sip_parse_obj(rr, headers); + return parse_rr(pkt); } -static void sip_parse_packet(byte *pkt, unsigned int len) +static int parse_udp(struct pkt *pkt) { - /* Parse IP header */ - if (len < 20) - { - fprintf(siplog, "\tVery truncated IP header\n"); - return; - } - unsigned int ipver = pkt[0] >> 4; - if (ipver != 4) - { - fprintf(siplog, "\tWe don't speak IPv%d\n", ipver); - return; - } - unsigned int hlen = (pkt[0] & 0x0f)*4; - if (len < hlen) - { - fprintf(siplog, "\tTruncated IP header (want %d)\n", hlen); - return; - } - unsigned int ilen = get_u16(pkt+2); - if (ilen > len) - { - fprintf(siplog, "\tTruncated (have %d, want %d)\n", len, ilen); - return; - } - len = ilen; - if (pkt[9] != 17) - { - fprintf(siplog, "\tNot UDP (protocol %02x)\n", pkt[9]); - return; - } - if (get_u16(pkt+6) & 0x3fff) - { - fprintf(siplog, "\tFragmented\n"); - return; - } - unsigned int saddr = get_u32(pkt+12); - unsigned int daddr = get_u32(pkt+16); - len -= hlen; - pkt += hlen; - - /* Parse UDP header */ - if (len < 8) - { - fprintf(siplog, "\tTruncated UDP header\n"); - return; - } - unsigned int sport = get_u16(pkt); - unsigned int dport = get_u16(pkt+2); - unsigned int ulen = get_u16(pkt+4); - if (len < ulen) - { - fprintf(siplog, "\tTruncated UDP data (have %d, want %d)\n", len, ulen); - return; - } - len = ulen-8; - pkt += 8; + byte *p = pkt->ip; + if (pkt->ip_len < 8) + return error(pkt, "Truncated UDP header"); + pkt->src_port = get_u16(p); + pkt->dst_port = get_u16(p+2); + uns ulen = get_u16(p+4); + if (ulen < 8) + return error(pkt, "Invalid UDP length (%d)", ulen); + if (ulen > pkt->ip_len) + return error(pkt, "Truncated UDP data (have %d, want %d)", pkt->ip_len, ulen); + pkt->udp = p + 8; + pkt->udp_len = ulen - 8; + debug("%08x:%d -> %08x:%d (%d bytes, out_p=%d)", pkt->src_addr, pkt->src_port, pkt->dst_addr, pkt->dst_port, pkt->out_p); + return parse_sip(pkt); +} - fprintf(siplog, "\t%08x:%d -> %08x:%d (%d bytes)\n", saddr, sport, daddr, dport, len); - sip_parse_header(pkt, len); +static int parse_ip(struct pkt *pkt) +{ + byte *p = pkt->raw; + if (pkt->raw_len < 20) + return error(pkt, "Very truncated IP header"); + uns ipver = p[0] >> 4; + if (ipver != 4) + return error(pkt, "We don't speak IPv%d", ipver); + uns hlen = (p[0] & 0x0f)*4; + if (pkt->raw_len < hlen) + return error(pkt, "Truncated IP header (want %d)", hlen); + uns ilen = get_u16(p+2); + if (ilen < hlen) + return error(pkt, "Invalid IP length (have %d, want at least %d for header)", ilen, hlen); + if (ilen > pkt->raw_len) + return error(pkt, "Truncated (have %d, want %d)", pkt->raw_len, ilen); + if (p[9] != 17) + return error(pkt, "Not UDP (protocol %02x)", p[9]); + if (get_u16(p+6) & 0x3fff) + return error(pkt, "Fragmented"); + pkt->ip = p + hlen; + pkt->ip_len = ilen - hlen; + pkt->src_addr = get_u32(p+12); + pkt->dst_addr = get_u32(p+16); + return parse_udp(pkt); } +/*** Interface to ulogd ***/ + static int sip_output(ulog_iret_t *res __attribute__((unused))) { + struct pkt pkt; + + char *prefix = (KEY_OK(K_OOB_PREFIX, STRING) ? KEY_VAL(K_OOB_PREFIX).ptr : "?"); + if (!strcasecmp(prefix, "phone-in")) + pkt.out_p = 0; + else if (!strcasecmp(prefix, "phone-out")) + pkt.out_p = 1; + else + { + if (verbose > 1) + fprintf(siplog, "(non-phone packet received, prefix=%s)\n", prefix); + return 0; + } + if (!KEY_OK(K_RAW_PKT, RAW) || !KEY_OK(K_RAW_PKTLEN, UINT32) || !KEY_OK(K_OOB_TIME_SEC, UINT32) || @@ -242,26 +291,20 @@ static int sip_output(ulog_iret_t *res __attribute__((unused))) ulogd_log(ULOGD_ERROR, "SIP: Mandatory keys missing\n"); return 1; } - - if (!KEY_OK(K_OOB_PREFIX, STRING) || strcasecmp(KEY_VAL(K_OOB_PREFIX).ptr, "phone")) - { - fprintf(siplog, "(non-phone packet received)\n"); - return 1; - } - - byte *pkt = KEY_VAL(K_RAW_PKT).ptr; - unsigned int len = KEY_VAL(K_RAW_PKTLEN).ui32; - time_t t = KEY_VAL(K_OOB_TIME_SEC).ui32; - struct tm *tm = localtime(&t); + pkt.raw = KEY_VAL(K_RAW_PKT).ptr; + pkt.raw_len = KEY_VAL(K_RAW_PKTLEN).ui32; + pkt.time_sec = KEY_VAL(K_OOB_TIME_SEC).ui32; + pkt.time_usec = KEY_VAL(K_OOB_TIME_USEC).ui32; + struct tm *tm = localtime(&pkt.time_sec); if (!tm) - fprintf(siplog, "<#%d> ", (int)t); + sprintf(pkt.time, "<#%d.%06d> ", (int)pkt.time_sec, pkt.time_usec); else - fprintf(siplog, "%04d-%02d-%02d %02d:%02d:%02d.%06d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, KEY_VAL(K_OOB_TIME_USEC).ui32); - fprintf(siplog, " [%d bytes]\n", len); - - sip_parse_packet(pkt, len); + sprintf(pkt.time, "%04d-%02d-%02d %02d:%02d:%02d.%06d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, pkt.time_usec); + if (verbose) + fprintf(siplog, "\t%s\n", pkt.time); + parse_ip(&pkt); fflush(siplog); return 0; }