1 /* $OpenBSD: pf-snit.c,v 1.8 2009/10/27 23:59:53 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 1993-96 Mats O Jansson. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include <sys/ioctl.h>
31 #include <sys/file.h>
32 #include <sys/socket.h>
33 #include <sys/uio.h>
34 #include <net/if.h>
35
36 #define DEV_NIT "/dev/nit"
37 #include <net/nit.h>
38 #include <net/nit_if.h>
39 #include <net/nit_pf.h>
40 #include <net/nit_buf.h>
41 #include <net/packetfilt.h>
42 #include <stropts.h>
43
44 #include <netinet/in.h>
45 #include <netinet/if_ether.h>
46
47 #include <netdb.h>
48 #include <ctype.h>
49 #include <syslog.h>
50
51 #include "common/mopdef.h"
52
53 /*
54 * Variables
55 */
56
57 /* struct ifreq ifr; */
58 extern int errno;
59 extern int promisc;
60
61 /*
62 * Return information to device.c how to open device.
63 * In this case the driver can handle both Ethernet type II and
64 * IEEE 802.3 frames (SNAP) in a single pfOpen.
65 */
66
67 int
pfTrans(interface)68 pfTrans(interface)
69 char *interface;
70 {
71 return TRANS_ETHER+TRANS_8023+TRANS_AND;
72 }
73
74 /*
75 * Open and initialize packet filter.
76 */
77
78 int
pfInit(interface,mode,protocol,trans)79 pfInit(interface, mode, protocol, trans)
80 char *interface;
81 u_short protocol;
82 int trans, mode;
83 {
84 int fd;
85 int ioarg;
86 char device[64];
87 unsigned long if_flags;
88
89 struct ifreq ifr;
90 struct strioctl si;
91
92 /* get clone */
93 if ((fd = open(DEV_NIT, mode)) < 0) {
94 syslog(LOG_ERR,"pfInit: open nit %m");
95 return(-1);
96 }
97
98 /*
99 * set filter for protocol
100 */
101
102 if (setup_pf(fd, protocol, trans) < 0)
103 return(-1);
104
105 /*
106 * set options, bind to underlying interface
107 */
108
109 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
110
111 /* bind */
112 si.ic_cmd = NIOCBIND; /* bind to underlying interface */
113 si.ic_timout = 10;
114 si.ic_len = sizeof(ifr);
115 si.ic_dp = (caddr_t)𝔦
116 if (ioctl(fd, I_STR, (caddr_t)&si) < 0) {
117 syslog(LOG_ERR,"pfinit: I_STR %m");
118 return(-1);
119 }
120
121 if (promisc) {
122 if_flags = NI_PROMISC;
123 si.ic_cmd = NIOCSFLAGS;
124 si.ic_timout = 10;
125 si.ic_len = sizeof(if_flags);
126 si.ic_dp = (caddr_t)&if_flags;
127 if (ioctl(fd, I_STR, (caddr_t)&si) < 0) {
128 syslog(LOG_ERR,"pfInit: I_STR (promisc) %m");
129 return(-1);
130 }
131 }
132
133 /* set up messages */
134 if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) { /* want messages */
135 syslog(LOG_ERR,"pfInit: I_SRDOPT %m");
136 return(-1);
137 }
138
139 /* flush read queue */
140 if (ioctl(fd, I_FLUSH, (char *)FLUSHR) < 0) {
141 syslog(LOG_ERR,"pfInit: I_FLUSH %m");
142 return(-1);
143 }
144
145 return(fd);
146 }
147
148 /*
149 * establish protocol filter
150 */
151
152 int
setup_pf(s,prot,trans)153 setup_pf(s, prot, trans)
154 int s, trans;
155 u_short prot;
156 {
157 int ioarg;
158 u_short offset;
159
160 struct packetfilt pf;
161 u_short *fwp = pf.Pf_Filter;
162 struct strioctl si;
163
164 #define s_offset(structp, element) (&(((structp)0)->element))
165
166 bzero(&pf, sizeof(pf));
167 pf.Pf_Priority = 128;
168
169 offset = ((int)s_offset(struct ether_header *, ether_type))/sizeof(u_short);
170 *fwp++ = ENF_PUSHWORD + offset; /* Check Ethernet type II */
171 *fwp++ = ENF_PUSHLIT | ENF_EQ; /* protocol prot */
172 *fwp++ = htons(prot);
173 *fwp++ = ENF_PUSHWORD + offset + 4; /* Check 802.3 protocol prot */
174 *fwp++ = ENF_PUSHLIT | ENF_EQ;
175 *fwp++ = htons(prot);
176 *fwp++ = ENF_PUSHWORD + offset + 1; /* Check for SSAP and DSAP */
177 *fwp++ = ENF_PUSHLIT | ENF_EQ;
178 *fwp++ = htons(0xaaaa);
179 *fwp++ = ENF_AND;
180 *fwp++ = ENF_OR;
181 pf.Pf_FilterLen = 11;
182
183 si.ic_cmd = NIOCSETF;
184 si.ic_timout = 10;
185 si.ic_len = sizeof(pf);
186 si.ic_dp = (char *)&pf;
187 if (ioctl(s, I_PUSH, "pf") < 0) {
188 syslog(LOG_ERR,"setup_pf: I_PUSH %m");
189 return(-1);
190 }
191 if (ioctl(s, I_STR, (char *)&si) < 0) {
192 syslog(LOG_ERR,"setup_pf: I_STR %m");
193 return(-1);
194 }
195
196 return(0);
197 }
198
199 /*
200 * Get the interface ethernet address
201 */
202
203 int
pfEthAddr(fd,addr)204 pfEthAddr(fd, addr)
205 int fd;
206 u_char *addr;
207 {
208 struct ifreq ifr;
209 struct sockaddr *sa;
210
211 if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
212 syslog(LOG_ERR,"pfEthAddr: SIOCGIFADDR %m");
213 return(-1);
214 }
215 sa = (struct sockaddr *)ifr.ifr_data;
216 bcopy((char *)sa->sa_data, (char *)addr, 6);
217
218 return(0);
219 }
220
221 /*
222 * Add a Multicast address to the interface
223 */
224
225 int
pfAddMulti(s,interface,addr)226 pfAddMulti(s, interface, addr)
227 int s;
228 char *interface, *addr;
229 {
230 struct ifreq ifr;
231 int fd;
232
233 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) -1);
234 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0;
235
236 ifr.ifr_addr.sa_family = AF_UNSPEC;
237 bcopy(addr, ifr.ifr_addr.sa_data, 6);
238
239 /*
240 * open a socket, temporarily, to use for SIOC* ioctls
241 */
242
243 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
244 syslog(LOG_ERR,"pfAddMulti: socket() %m");
245 return(-1);
246 }
247 if (ioctl(fd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
248 syslog(LOG_ERR,"pfAddMulti: SIOCADDMULTI %m");
249 close(fd);
250 return(-1);
251 }
252 close(fd);
253
254 return(0);
255 }
256
257 /*
258 * delete a multicast address from the interface
259 */
260
261 int
pfDelMulti(s,interface,addr)262 pfDelMulti(s, interface, addr)
263 int s;
264 char *interface, *addr;
265 {
266 struct ifreq ifr;
267 int fd;
268
269 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) -1);
270 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0;
271
272 ifr.ifr_addr.sa_family = AF_UNSPEC;
273 bcopy(addr, ifr.ifr_addr.sa_data, 6);
274
275 /*
276 * open a socket, temporarily, to use for SIOC* ioctls
277 *
278 */
279 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
280 syslog(LOG_ERR,"pfDelMulti: socket() %m");
281 return(-1);
282 }
283
284 if (ioctl(fd, SIOCDELMULTI, (caddr_t)&ifr) < 0) {
285 syslog(LOG_ERR,"pfDelMulti: SIOCDELMULTI %m");
286 close(fd);
287 return(-1);
288 }
289 close(fd);
290
291 return(0);
292 }
293
294 /*
295 * read a packet
296 */
297
298 int
pfRead(fd,buf,len)299 pfRead(fd, buf, len)
300 int fd, len;
301 u_char *buf;
302 {
303 return(read(fd, buf, len));
304 }
305
306 /*
307 * write a packet
308 */
309
310 int
pfWrite(fd,buf,len,trans)311 pfWrite(fd, buf, len, trans)
312 int fd, len, trans;
313 u_char *buf;
314 {
315
316 struct sockaddr sa;
317 struct strbuf pbuf, dbuf;
318
319 sa.sa_family = AF_UNSPEC;
320 bcopy(buf, sa.sa_data, sizeof(sa.sa_data));
321
322 switch (trans) {
323 default:
324 pbuf.len = sizeof(struct sockaddr);
325 pbuf.buf = (char *) &sa;
326 dbuf.len = len-14;
327 dbuf.buf = (char *)buf+14;
328 break;
329 }
330
331 if (putmsg(fd, &pbuf, &dbuf, 0) == 0)
332 return(len);
333
334 return(-1);
335 }
336