1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6
7 typedef struct Hdr Hdr;
8 struct Hdr
9 {
10 uchar sport[2];
11 uchar dport[2];
12 uchar seq[4];
13 uchar ack[4];
14 uchar flag[2];
15 uchar win[2];
16 uchar cksum[2];
17 uchar urg[2];
18 uchar opt[1];
19 };
20
21 typedef struct PseudoHdr{
22 uchar src[4];
23 uchar dst[4];
24 uchar zero;
25 uchar proto;
26 uchar length[2];
27 uchar hdrdata[1580];
28 } PseudoHdr;
29
30 enum
31 {
32 TCPLEN= 20,
33 };
34
35 enum
36 {
37 Os,
38 Od,
39 Osd,
40 };
41
42 static Field p_fields[] =
43 {
44 {"s", Fnum, Os, "source port", } ,
45 {"d", Fnum, Od, "dest port", } ,
46 {"a", Fnum, Osd, "source/dest port", } ,
47 {"sd", Fnum, Osd, "source/dest port", } ,
48 {0}
49 };
50
51 static Mux p_mux[] =
52 {
53 {"dns", 53, },
54 {"ninep", 17007, }, /* exportfs */
55 {"ninep", 564, }, /* 9fs */
56 {"ninep", 17005, }, /* ocpu */
57 {"ninep", 17010, }, /* ncpu */
58 {"ninep", 17013, }, /* cpu */
59 {0},
60 };
61
62 enum
63 {
64 EOLOPT = 0,
65 NOOPOPT = 1,
66 MSSOPT = 2,
67 MSS_LENGTH = 4, /* Mean segment size */
68 WSOPT = 3,
69 WS_LENGTH = 3, /* Bits to scale window size by */
70 };
71
72 static void
p_compile(Filter * f)73 p_compile(Filter *f)
74 {
75 Mux *m;
76
77 if(f->op == '='){
78 compile_cmp(tcp.name, f, p_fields);
79 return;
80 }
81 for(m = p_mux; m->name != nil; m++)
82 if(strcmp(f->s, m->name) == 0){
83 f->pr = m->pr;
84 f->ulv = m->val;
85 f->subop = Osd;
86 return;
87 }
88 sysfatal("unknown tcp field or protocol: %s", f->s);
89 }
90
91 static int
p_filter(Filter * f,Msg * m)92 p_filter(Filter *f, Msg *m)
93 {
94 Hdr *h;
95
96 if(m->pe - m->ps < TCPLEN)
97 return 0;
98
99 h = (Hdr*)m->ps;
100 m->ps += (NetS(h->flag)>>10) & 0x3f;
101
102 switch(f->subop){
103 case Os:
104 return NetS(h->sport) == f->ulv;
105 case Od:
106 return NetS(h->dport) == f->ulv;
107 case Osd:
108 return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
109 }
110 return 0;
111 }
112
113 enum
114 {
115 URG = 0x20, /* Data marked urgent */
116 ACK = 0x10, /* Aknowledge is valid */
117 PSH = 0x08, /* Whole data pipe is pushed */
118 RST = 0x04, /* Reset connection */
119 SYN = 0x02, /* Pkt. is synchronise */
120 FIN = 0x01, /* Start close down */
121 };
122
123 static char*
flags(int f)124 flags(int f)
125 {
126 static char fl[20];
127 char *p;
128
129 p = fl;
130 if(f & URG)
131 *p++ = 'U';
132 if(f & ACK)
133 *p++ = 'A';
134 if(f & PSH)
135 *p++ = 'P';
136 if(f & RST)
137 *p++ = 'R';
138 if(f & SYN)
139 *p++ = 'S';
140 if(f & FIN)
141 *p++ = 'F';
142 *p = 0;
143 return fl;
144 }
145
146
147 static int
p_seprint(Msg * m)148 p_seprint(Msg *m)
149 {
150 int dport, sport, len, flag, optlen;
151 uchar *optr;
152 Hdr *h;
153
154 if(m->pe - m->ps < TCPLEN)
155 return -1;
156 h = (Hdr*)m->ps;
157
158 /* get tcp header length */
159 flag = NetS(h->flag);
160 len = (flag>>10) & ~3;
161 flag &= 0x3ff;
162 m->ps += len;
163
164 /* next protocol */
165 dport = NetS(h->dport);
166 sport = NetS(h->sport);
167 demux(p_mux, sport, dport, m, &dump);
168
169 m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
170 NetS(h->sport), dport,
171 (ulong)NetL(h->seq), (ulong)NetL(h->ack),
172 flags(flag), NetS(h->win),
173 NetS(h->cksum));
174
175 /* tcp options */
176 len -= TCPLEN;
177 optr = h->opt;
178 while(len > 0) {
179 if(*optr == EOLOPT){
180 m->p = seprint(m->p, m->e, " opt=EOL");
181 break;
182 }
183 if(*optr == NOOPOPT) {
184 m->p = seprint(m->p, m->e, " opt=NOOP");
185 len--;
186 optr++;
187 continue;
188 }
189 optlen = optr[1];
190 if(optlen < 2 || optlen > len)
191 break;
192 switch(*optr) {
193 case MSSOPT:
194 m->p = seprint(m->p, m->e, " opt%d=(mss %ud)",
195 optlen, nhgets(optr+2));
196 break;
197 case WSOPT:
198 m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)",
199 optlen, *(optr+2));
200 break;
201 default:
202 m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)",
203 optlen, *optr, optlen-2, optr+2);
204 }
205 len -= optlen;
206 optr += optlen;
207 }
208 return 0;
209 }
210
211 Proto tcp =
212 {
213 "tcp",
214 p_compile,
215 p_filter,
216 p_seprint,
217 p_mux,
218 "%lud",
219 p_fields,
220 defaultframer,
221 };
222