]> mj.ucw.cz Git - siplog.git/commitdiff
The big cleanup.
authorMartin Mares <mj@ucw.cz>
Sun, 6 Jan 2008 18:56:17 +0000 (19:56 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 6 Jan 2008 18:56:17 +0000 (19:56 +0100)
siplog.c

index 81d36a8a8666a796db3fe1b111bdce85f495bf8b..c45847169339ef597a0f7ced9cb4a09e41b98acc 100644 (file)
--- a/siplog.c
+++ b/siplog.c
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
+#include <stdarg.h>
 #include <signal.h>
 #include <time.h>
 #include <alloca.h>
 #include <ulogd/conffile.h>
 
 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; i<len; i++)
-    fputc(p[i], siplog);
-  fprintf(siplog, "----\n");
-#endif
+static int parse_sip(struct pkt *pkt)
+{
+  char *p = (char*) pkt->udp;
+  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;
 }