2 * A Simple SIP Logging Plugin for ulogd
4 * (c) 2008 Martin Mares <mj@ucw.cz>
13 #include <ulogd/ulogd.h>
14 #include <ulogd/conffile.h>
16 typedef unsigned char byte;
18 /*** Configuration ***/
20 static config_entry_t sip_cf_log = {
23 .type = CONFIG_TYPE_STRING,
24 .options = CONFIG_OPT_NONE,
25 .u.string = "/var/log/ulog/sip.log"
28 /*** Unaligned access ***/
30 static unsigned int get_u16(byte *p)
32 return (p[0] << 8) | p[1];
35 static unsigned int get_u32(byte *p)
37 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
48 { "oob.time.sec", 0 },
49 { "oob.time.usec", 0 },
61 static int init_keys(void)
63 for (unsigned int i=0; i < sizeof(keys)/sizeof(keys[0]); i++)
64 if (!(keys[i].id = keyh_getid(keys[i].name)))
66 ulogd_log(ULOGD_ERROR, "SIP: Unable to resolve key %s\n", keys[i].name);
72 #define KEY_H(i) ulogd_keyh[keys[i].id].interp->result[ulogd_keyh[keys[i].id].offset]
73 #define KEY_VAL(i) KEY_H(i).value
74 #define KEY_FLAGS(i) KEY_H(i).flags
75 #define KEY_TYPE(i) KEY_H(i).type
76 #define KEY_OK(i,t) ((KEY_FLAGS(i) & ULOGD_RETF_VALID) && KEY_TYPE(i) == ULOGD_RET_##t)
87 static void sip_parse_obj(char *rr, struct hdr *headers)
91 static void sip_parse_header(byte *pkt, unsigned int len)
93 char *p = (char*) pkt;
95 struct hdr *headers = NULL;
98 for (unsigned int i=0; i<len; i++)
100 fprintf(siplog, "----\n");
103 // Parse the request/reply line first
105 while (p < end && *p != '\r' && *p != '\n')
109 fprintf(siplog, "\tTruncated 1st line\n");
114 if (p < end && *p == '\n')
116 fprintf(siplog, "\t>>> %s\n", rr);
118 // Slurp the other header lines
127 fprintf(siplog, "\tTruncated SIP headers\n");
135 if (p < end && (*p == ' ' || *p == '\t'))
148 // fprintf(siplog, "\tH: %s\n", start);
149 // Got a line, parse it
150 char *sep = strchr(start, ':');
153 fprintf(siplog, "\tMalformed header line\n");
157 for (char *p=sep; p>start && (p[-1] == ' ' || p[-1] == '\t');)
159 while (++sep < end && (*sep == ' ' || *sep == '\t'))
161 fprintf(siplog, "\t%s: %s\n", start, sep);
162 struct hdr *h = alloca(sizeof(*h));
169 sip_parse_obj(rr, headers);
172 static void sip_parse_packet(byte *pkt, unsigned int len)
174 /* Parse IP header */
177 fprintf(siplog, "\tVery truncated IP header\n");
180 unsigned int ipver = pkt[0] >> 4;
183 fprintf(siplog, "\tWe don't speak IPv%d\n", ipver);
186 unsigned int hlen = (pkt[0] & 0x0f)*4;
189 fprintf(siplog, "\tTruncated IP header (want %d)\n", hlen);
192 unsigned int ilen = get_u16(pkt+2);
195 fprintf(siplog, "\tTruncated (have %d, want %d)\n", len, ilen);
201 fprintf(siplog, "\tNot UDP (protocol %02x)\n", pkt[9]);
204 if (get_u16(pkt+6) & 0x3fff)
206 fprintf(siplog, "\tFragmented\n");
209 unsigned int saddr = get_u32(pkt+12);
210 unsigned int daddr = get_u32(pkt+16);
214 /* Parse UDP header */
217 fprintf(siplog, "\tTruncated UDP header\n");
220 unsigned int sport = get_u16(pkt);
221 unsigned int dport = get_u16(pkt+2);
222 unsigned int ulen = get_u16(pkt+4);
225 fprintf(siplog, "\tTruncated UDP data (have %d, want %d)\n", len, ulen);
231 fprintf(siplog, "\t%08x:%d -> %08x:%d (%d bytes)\n", saddr, sport, daddr, dport, len);
232 sip_parse_header(pkt, len);
235 static int sip_output(ulog_iret_t *res __attribute__((unused)))
237 if (!KEY_OK(K_RAW_PKT, RAW) ||
238 !KEY_OK(K_RAW_PKTLEN, UINT32) ||
239 !KEY_OK(K_OOB_TIME_SEC, UINT32) ||
240 !KEY_OK(K_OOB_TIME_USEC, UINT32))
242 ulogd_log(ULOGD_ERROR, "SIP: Mandatory keys missing\n");
246 if (!KEY_OK(K_OOB_PREFIX, STRING) || strcasecmp(KEY_VAL(K_OOB_PREFIX).ptr, "phone"))
248 fprintf(siplog, "(non-phone packet received)\n");
252 byte *pkt = KEY_VAL(K_RAW_PKT).ptr;
253 unsigned int len = KEY_VAL(K_RAW_PKTLEN).ui32;
254 time_t t = KEY_VAL(K_OOB_TIME_SEC).ui32;
255 struct tm *tm = localtime(&t);
257 fprintf(siplog, "<#%d> ", (int)t);
259 fprintf(siplog, "%04d-%02d-%02d %02d:%02d:%02d.%06d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
260 tm->tm_hour, tm->tm_min, tm->tm_sec, KEY_VAL(K_OOB_TIME_USEC).ui32);
261 fprintf(siplog, " [%d bytes]\n", len);
263 sip_parse_packet(pkt, len);
269 /*** Housekeeping ***/
271 static int sip_init(void)
273 if (config_parse_file("SIP", &sip_cf_log))
275 ulogd_log(ULOGD_ERROR, "SIP: Parsing of configuration file failed\n");
278 ulogd_log(ULOGD_INFO, "Initializing SIP plugin, logging to %s\n", sip_cf_log.u.string);
279 siplog = fopen(sip_cf_log.u.string, "a");
282 ulogd_log(ULOGD_ERROR, "Cannot open %s: %s", sip_cf_log.u.string, strerror(errno));
288 static void sip_fini(void)
290 // Logging does not work here
291 // ulogd_log(ULOGD_INFO, "siplog fini\n");
295 static void sip_signal(int sig)
299 // FIXME: Should reopen the log file here
303 static ulog_output_t sip_op = {
307 .output = sip_output,
311 static void __attribute__((constructor)) constr(void)
313 // All logging goes to stderr instead of the log file
314 // ulogd_log(ULOGD_INFO, "Registered siplog plugin\n");
316 register_output(&sip_op);