]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/snoopy/tcp.c
snoopy(8): add support for dhcp classless static routes option
[plan9front.git] / sys / src / cmd / ip / snoopy / tcp.c
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
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
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*
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
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 };