]> mj.ucw.cz Git - netgrind.git/blob - netgrind/save.c
HTTP parsing. Detecting partial closes.
[netgrind.git] / netgrind / save.c
1 /*
2  *      Netgrind -- Saving to Files
3  *
4  *      (c) 2003 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "netgrind/pkt.h"
12 #include "netgrind/netgrind.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <time.h>
18 #include <netinet/in.h>
19
20 byte *save_dir;
21
22 void format_timestamp(byte *buf, u64 time)
23 {
24   struct tm *tm;
25   time_t t = time / 1000000;
26   tm = localtime(&t);
27   ASSERT(tm);
28   int len = strftime(buf, TIMESTAMP_LEN, "%Y-%m-%d %H:%M:%S", tm);
29   ASSERT(len);
30   sprintf(buf+len, ".%03d", (uns)(time%1000000)/1000);
31 }
32
33 void sink_open(struct flow *f UNUSED, u64 when UNUSED)
34 {
35 }
36
37 void sink_close(struct flow *f UNUSED, int cause UNUSED, u64 when UNUSED)
38 {
39 }
40
41 void sink_input(struct flow *f UNUSED, int dir UNUSED, struct pkt *p)
42 {
43   pkt_free(p);
44 }
45
46 struct appl_hooks appl_sink = {
47   .open = sink_open,
48   .input = sink_input,
49   .close = sink_close
50 };
51
52 struct save_state {
53   FILE *file[2];
54 };
55
56 static void save_open(struct flow *f, u64 when UNUSED)
57 {
58   struct save_state *s = xmalloc(sizeof(*s));
59   static uns save_counter;
60   for (uns dir=0; dir<2; dir++)
61     {
62       byte name[256];
63       sprintf(name, "%s/%06u-%d.%d.%d.%d:%d-%d.%d.%d.%d:%d-%c", save_dir, save_counter,
64               IPQUAD(f->saddr), ntohs(f->sport), IPQUAD(f->daddr), ntohs(f->dport),
65               'A' + dir);
66       if (!(s->file[dir] = fopen(name, "w")))
67         die("Unable to create %s: %m", name);
68     }
69   f->appl_data = s;
70   save_counter++;
71 }
72
73 static void save_close(struct flow *f, int cause UNUSED, u64 when UNUSED)
74 {
75   struct save_state *s = f->appl_data;
76   fclose(s->file[0]);
77   fclose(s->file[1]);
78   xfree(s);
79 }
80
81 static void save_input(struct flow *f, int dir, struct pkt *p)
82 {
83   struct save_state *s = f->appl_data;
84   fwrite(p->data, pkt_len(p), 1, s->file[dir]);
85   pkt_free(p);
86 }
87
88 struct appl_hooks appl_save = {
89   .open = save_open,
90   .input = save_input,
91   .close = save_close
92 };
93
94 uns asave_width = 80;
95
96 struct asave_state {
97   FILE *file;
98   u64 start_time;
99 };
100
101 static void asave_event(struct asave_state *s, u64 time, byte *msg, ...)
102 {
103   va_list args;
104
105   va_start(args, msg);
106   time -= s->start_time;
107   fprintf(s->file, "%04d.%03d ", (int)(time/1000000), (int)(time%1000000)/1000);
108   vfprintf(s->file, msg, args);
109   va_end(args);
110 }
111
112 static void asave_open(struct flow *f, u64 when)
113 {
114   struct asave_state *s = xmalloc(sizeof(*s));
115   byte name[256], stamp[TIMESTAMP_LEN];
116   static uns asave_counter;
117   sprintf(name, "%s/%06u-%d.%d.%d.%d:%d-%d.%d.%d.%d:%d", save_dir, asave_counter++,
118           IPQUAD(f->saddr), ntohs(f->sport),
119           IPQUAD(f->daddr), ntohs(f->dport));
120   if (!(s->file = fopen(name, "w")))
121     die("Unable to create %s: %m", name);
122   f->appl_data = s;
123   s->start_time = when;
124   asave_event(s, when, "Connection: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n",
125               IPQUAD(f->saddr), ntohs(f->sport), IPQUAD(f->daddr), ntohs(f->dport));
126   format_timestamp(stamp, when);
127   asave_event(s, when, "Initiated on: %s\n", stamp);
128 }
129
130 static void asave_close(struct flow *f, int cause, u64 when)
131 {
132   struct asave_state *s = f->appl_data;
133   static byte *close_reasons[] = { "Close", "Connection reset", "Timeout", "Doomsday", "Corrupted" };
134   asave_event(s, when, "Terminated: %s\n", close_reasons[cause]);
135   asave_event(s, when, "TX %Ld bytes in %Ld packets, RX %Ld bytes in %Ld packets\n",
136               f->pipe[1].stat.bytes, f->pipe[1].stat.packets,
137               f->pipe[0].stat.bytes, f->pipe[0].stat.packets);
138   asave_event(s, when, "Transferred %Ld bytes, TCP overhead %Ld bytes\n",
139               f->pipe[0].stat.bytes + f->pipe[1].stat.bytes,
140               f->stat_raw.bytes - (f->pipe[0].stat.bytes + f->pipe[1].stat.bytes));
141   fclose(s->file);
142   xfree(s);
143 }
144
145 static void asave_input(struct flow *f, int dir, struct pkt *p)
146 {
147   struct asave_state *s = f->appl_data;
148
149   if (!pkt_len(p))
150     {
151       asave_event(s, p->timestamp, "%s FIN\n", (dir ? ">>" : "<<"));
152       return;
153     }
154
155   asave_event(s, p->timestamp, (dir ? ">>> " : "<<< "));
156   uns len = pkt_len(p);
157   uns cnt = 0;
158   for (uns i=0; i<len; i++)
159     {
160       uns c = p->data[i];
161       if (c == '\n')
162         cnt = ~0U;
163       else if (c >= 0x20 && c < 0x7f || c >= 0xa0)
164         {
165           fputc(c, s->file);
166           cnt++;
167         }
168       else
169         {
170           fprintf(s->file, "<%02x>", c);
171           cnt += 4;
172         }
173       if (cnt >= asave_width+10 || (cnt == asave_width && i < len-1 && p->data[i+1] != '\n'))
174         {
175           if (c != '\n')
176             fputc('\\', s->file);
177           fputc('\n', s->file);
178           if (i < len-1)
179             asave_event(s, p->timestamp, (dir ? ">>> " : "<<< "));
180           cnt = 0;
181         }
182     }
183   if (cnt)
184     {
185       fputc('\\', s->file);
186       fputc('\n', s->file);
187     }
188   pkt_free(p);
189 }
190
191 struct appl_hooks appl_asave = {
192   .open = asave_open,
193   .input = asave_input,
194   .close = asave_close
195 };
196
197 struct summary_state {
198   u64 estab_time;
199 };
200
201 static void summary_open(struct flow *f, u64 when)
202 {
203   struct summary_state *s = xmalloc(sizeof(*s));
204   f->appl_data = s;
205   s->estab_time = when;
206 }
207
208 static void summary_close(struct flow *f, int cause, u64 when)
209 {
210   static int summary_cnt;
211   if (!summary_cnt++)
212     printf("# timestamp             source                destination              elapsed close   tx      rx  oh    KB/s\n");
213          /* 2003-06-06 22:38:34.076 81.27.194.19:1165     195.113.31.123:22          1.604 OK    1991   12656  11%  8.914 */
214
215   struct summary_state *s = f->appl_data;
216   u64 duration = when - s->estab_time;
217   byte src[22], dst[22];
218   byte stamp[TIMESTAMP_LEN];
219   static byte *sum_causes[] = { "OK", "RE", "TO", "DD", "CO" };
220   format_timestamp(stamp, s->estab_time);
221   sprintf(src, "%d.%d.%d.%d:%d", IPQUAD(f->saddr), ntohs(f->sport));
222   sprintf(dst, "%d.%d.%d.%d:%d", IPQUAD(f->daddr), ntohs(f->dport));
223   double braw = f->stat_raw.bytes;
224   double beff = f->pipe[0].stat.bytes + f->pipe[1].stat.bytes;
225   double over = 100 * ((braw - beff) / braw);
226   double avs = duration ? ((beff / ((double)duration/1000000)) / 1024) : 1e30;
227   printf("%s %-21s %-21s %6d.%03d %s %7Ld %7Ld %3d%% ",
228          stamp, src, dst,
229          (uns)(duration/1000000), (uns)(duration%1000000)/1000, sum_causes[cause],
230          f->pipe[1].stat.bytes, f->pipe[0].stat.bytes,
231          CLAMP((int)over,0,100));
232   printf((avs < 100) ? "%6.3f" : "%6.0f", MIN(avs, 999999));
233   putchar('\n');
234   xfree(s);
235 }
236
237 struct appl_hooks appl_summary = {
238   .open = summary_open,
239   .input = sink_input,
240   .close = summary_close
241 };