]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ipfilter/ipsd/sdlpi.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ipfilter / ipsd / sdlpi.c
1 /*      $FreeBSD$       */
2
3 /*
4  * (C)opyright 1992-1998 Darren Reed. (from tcplog)
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  *
8  */
9
10 #include <stdio.h>
11 #include <netdb.h>
12 #include <ctype.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/timeb.h>
19 #include <sys/socket.h>
20 #include <sys/file.h>
21 #include <sys/ioctl.h>
22 #include <sys/stropts.h>
23
24 #include <sys/pfmod.h>
25 #include <sys/bufmod.h>
26 #include <sys/dlpi.h>
27
28 #include <net/if.h>
29 #include <netinet/in.h>
30 #include <netinet/in_systm.h>
31 #include <netinet/ip.h>
32 #include <netinet/if_ether.h>
33 #include <netinet/ip_var.h>
34 #include <netinet/udp.h>
35 #include <netinet/udp_var.h>
36 #include <netinet/tcp.h>
37 #include <netinet/tcpip.h>
38
39 #include "ip_compat.h"
40
41 #ifndef lint
42 static  char    snitid[] = "%W% %G% (C)1995 Darren Reed";
43 #endif
44
45 #define BUFSPACE        32768
46
47 static  int     solfd;
48
49 /*
50  * Be careful to only include those defined in the flags option for the
51  * interface are included in the header size.
52  */
53 static  int     timeout;
54
55
56 void    nullbell()
57 {
58         return 0;
59 }
60
61
62 int     ack_recv(ep)
63 char    *ep;
64 {
65         struct  tcpiphdr        tip;
66         tcphdr_t        *tcp;
67         ip_t    *ip;
68
69         ip = (ip_t *)&tip;
70         tcp = (tcphdr_t *)(ip + 1);
71         bcopy(ep, (char *)ip, sizeof(*ip));
72         bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp));
73
74         if (ip->ip_off & 0x1fff != 0)
75                 return 0;
76         if (0 == detect(ip, tcp))
77                 return 1;
78         return 0;
79 }
80
81
82 int     readloop(fd, port, dst)
83 int     fd, port;
84 struct  in_addr dst;
85 {
86         static  u_char  buf[BUFSPACE];
87         register u_char *bp, *cp, *bufend;
88         register struct sb_hdr  *hp;
89         register int    cc;
90         struct  strbuf  dbuf;
91         ether_header_t  eh;
92         time_t  now = time(NULL);
93         int     flags = 0, i, done = 0;
94
95         fd = solfd;
96         dbuf.len = 0;
97         dbuf.buf = buf;
98         dbuf.maxlen = sizeof(buf);
99         /*
100          * no control data buffer...
101          */
102         while (1) {
103                 (void) signal(SIGALRM, nullbell);
104                 alarm(1);
105                 i = getmsg(fd, NULL, &dbuf, &flags);
106                 alarm(0);
107                 (void) signal(SIGALRM, nullbell);
108
109                 cc = dbuf.len;
110                 if ((time(NULL) - now) > timeout)
111                         return done;
112                 if (i == -1)
113                         if (errno == EINTR)
114                                 continue;
115                         else
116                                 break;
117                 bp = buf;
118                 bufend = buf + cc;
119                 /*
120                  * loop through each snapshot in the chunk
121                  */
122                 while (bp < bufend) {
123                         /*
124                          * get past bufmod header
125                          */
126                         hp = (struct sb_hdr *)bp;
127                         cp = (u_char *)((char *)bp + sizeof(*hp));
128                         bcopy(cp, (char *)&eh, sizeof(eh));
129                         /*
130                          * next snapshot
131                          */
132                         bp += hp->sbh_totlen;
133                         cc -= hp->sbh_totlen;
134
135                         if (eh.ether_type != ETHERTYPE_IP)
136                                 continue;
137
138                         cp += sizeof(eh);
139                         done += ack_recv(cp);
140                 }
141                 alarm(1);
142         }
143         perror("getmsg");
144         exit(-1);
145 }
146
147 int     initdevice(device, tout)
148 char    *device;
149 int     tout;
150 {
151         struct  strioctl si;
152         struct  timeval to;
153         struct  ifreq ifr;
154         struct  packetfilt pfil;
155         u_long  if_flags;
156         u_short *fwp = pfil.Pf_Filter;
157         char    devname[16], *s, buf[256];
158         int     i, offset, fd, snaplen= 58, chunksize = BUFSPACE;
159
160         (void) sprintf(devname, "/dev/%s", device);
161
162         s = devname + 5;
163         while (*s && !ISDIGIT(*s))
164                 s++;
165         if (!*s)
166             {
167                 fprintf(stderr, "bad device name %s\n", devname);
168                 exit(-1);
169             }
170         i = atoi(s);
171         *s = '\0';
172         /*
173          * For reading
174          */
175         if ((fd = open(devname, O_RDWR)) < 0)
176             {
177                 fprintf(stderr, "O_RDWR(0) ");
178                 perror(devname);
179                 exit(-1);
180             }
181         if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1)
182             {
183                 fprintf(stderr, "DLPI error\n");
184                 exit(-1);
185             }
186         dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0);
187         dlbindack(fd, buf);
188         /*
189          * read full headers
190          */
191         if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1)
192             {
193                 fprintf(stderr, "DLIOCRAW error\n");
194                 exit(-1);
195             }
196         /*
197          * Create some filter rules for our TCP watcher. We only want ethernet
198          * pacets which are IP protocol and only the TCP packets from IP.
199          */
200         offset = 6;
201         *fwp++ = ENF_PUSHWORD + offset;
202         *fwp++ = ENF_PUSHLIT | ENF_CAND;
203         *fwp++ = htons(ETHERTYPE_IP);
204         *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
205         *fwp++ = ENF_PUSHLIT | ENF_AND;
206         *fwp++ = htons(0x00ff);
207         *fwp++ = ENF_PUSHLIT | ENF_COR;
208         *fwp++ = htons(IPPROTO_TCP);
209         *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
210         *fwp++ = ENF_PUSHLIT | ENF_AND;
211         *fwp++ = htons(0x00ff);
212         *fwp++ = ENF_PUSHLIT | ENF_CAND;
213         *fwp++ = htons(IPPROTO_UDP);
214         pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]);
215         /*
216          * put filter in place.
217          */
218
219         if (ioctl(fd, I_PUSH, "pfmod") == -1)
220             {
221                 perror("ioctl: I_PUSH pf");
222                 exit(1);
223             }
224         if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1)
225             {
226                 perror("ioctl: PFIOCSETF");
227                 exit(1);
228             }
229
230         /*
231          * arrange to get messages from the NIT STREAM and use NIT_BUF option
232          */
233         if (ioctl(fd, I_PUSH, "bufmod") == -1)
234             {
235                 perror("ioctl: I_PUSH bufmod");
236                 exit(1);
237             }
238         i = 128;
239         strioctl(fd, SBIOCSSNAP, -1, sizeof(i), (char *)&i);
240         /*
241          * set the timeout
242          */
243         to.tv_sec = 1;
244         to.tv_usec = 0;
245         if (strioctl(fd, SBIOCSTIME, -1, sizeof(to), (char *)&to) == -1)
246             {
247                 perror("strioctl(SBIOCSTIME)");
248                 exit(-1);
249             }
250         /*
251          * flush read queue
252          */
253         if (ioctl(fd, I_FLUSH, FLUSHR) == -1)
254             {
255                 perror("I_FLUSHR");
256                 exit(-1);
257             }
258         timeout = tout;
259         solfd = fd;
260         return fd;
261 }