xref: /openbsd/usr.sbin/mopd/otherOS/pf-snit.c (revision 043fbe51)
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)&ifr;
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