xref: /openbsd-src/usr.sbin/mopd/common/pf.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1 /*	$OpenBSD: pf.c,v 1.11 2004/05/08 20:23:21 canacar Exp $ */
2 
3 /*
4  * Copyright (c) 1993-95 Mats O Jansson.  All rights reserved.
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is partly derived from rarpd.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef LINT
32 static const char rcsid[] =
33     "$OpenBSD: pf.c,v 1.11 2004/05/08 20:23:21 canacar Exp $";
34 #endif
35 
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/ioctl.h>
41 #include <sys/file.h>
42 #include <sys/socket.h>
43 #include <sys/uio.h>
44 #include <net/if.h>
45 
46 #include <net/bpf.h>
47 #include <sys/errno.h>
48 
49 #include <netinet/in.h>
50 #include <netinet/if_ether.h>
51 
52 #include <netdb.h>
53 #include <ctype.h>
54 #include <string.h>
55 #include <err.h>
56 
57 #include <syslog.h>
58 
59 #include "common/mopdef.h"
60 
61 /*
62  * Variables
63  */
64 
65 extern int promisc;
66 
67 /*
68  * Return information to device.c how to open device.
69  * In this case the driver can handle both Ethernet type II and
70  * IEEE 802.3 frames (SNAP) in a single pfOpen.
71  */
72 
73 int
74 pfTrans(char *interface)
75 {
76 	return (TRANS_ETHER + TRANS_8023 + TRANS_AND);
77 }
78 
79 /*
80  * Open and initialize packet filter.
81  */
82 int
83 pfInit(char *interface, int mode, u_short protocol, int typ)
84 {
85 	int		fd;
86 	int		n = 0;
87 	char		device[sizeof "/dev/bpf000"];
88 	struct ifreq	ifr;
89 	u_int		dlt;
90 	int		immediate;
91 
92 	static struct bpf_insn insns[] = {
93 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12),
94 		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 4, 0),
95 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20),
96 		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 0, 3),
97 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 14),
98 		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xaaaa, 0, 1),
99 		BPF_STMT(BPF_RET | BPF_K, 1520),
100 		BPF_STMT(BPF_RET | BPF_K, 0),
101 	};
102 	static struct bpf_program filter = {
103 		sizeof insns / sizeof(insns[0]),
104 		insns
105 	};
106 
107 	/* Go through all the minors and find one that isn't in use. */
108 	do {
109 		snprintf(device, sizeof device, "/dev/bpf%d", n++);
110 		fd = open(device, mode);
111 	} while (fd < 0 && errno == EBUSY);
112 
113 	if (fd < 0) {
114 		syslog(LOG_ERR,"pfInit: open bpf %m");
115 		return (-1);
116 	}
117 
118 	/* Set immediate mode so packets are processed as they arrive. */
119 	immediate = 1;
120 	if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
121 		syslog(LOG_ERR,"pfInit: BIOCIMMEDIATE: %m");
122 		return (-1);
123 	}
124 	strncpy(ifr.ifr_name, interface, sizeof ifr.ifr_name);
125 	if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) {
126 		syslog(LOG_ERR,"pfInit: BIOCSETIF: %m");
127 		return (-1);
128 	}
129 	/* Check that the data link layer is an Ethernet; this code won't work
130 	 * with anything else. */
131 	if (ioctl(fd, BIOCGDLT, (caddr_t)&dlt) < 0) {
132 		syslog(LOG_ERR,"pfInit: BIOCGDLT: %m");
133 		return (-1);
134 	}
135 	if (dlt != DLT_EN10MB) {
136 		syslog(LOG_ERR,"pfInit: %s is not ethernet", device);
137 		return (-1);
138 	}
139 	if (promisc)
140 		/* Set promiscuous mode. */
141 		if (ioctl(fd, BIOCPROMISC, (caddr_t)0) < 0) {
142 			syslog(LOG_ERR,"pfInit: BIOCPROMISC: %m");
143 			return (-1);
144 		}
145 
146 	/* Set filter program. */
147 	insns[1].k = protocol;
148 	insns[3].k = protocol;
149 
150 	if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) {
151 		syslog(LOG_ERR,"pfInit: BIOCSETF: %m");
152 		return (-1);
153 	}
154 
155 	/* XXX set the same write filter (for protocol only) */
156 	if (ioctl(fd, BIOCSETWF, (caddr_t) & filter) < 0) {
157 		syslog(LOG_ERR,"pfInit: BIOCSETWF: %m");
158 		return (-1);
159 	}
160 
161 	/* Lock the interface to prevent further changes */
162 	if (ioctl(fd, BIOCLOCK) < 0) {
163 		syslog(LOG_ERR,"pfInit: BIOCLOCK: %m");
164 		return (-1);
165 	}
166 
167 	return (fd);
168 }
169 
170 /*
171  * Add a Multicast address to the interface
172  */
173 int
174 pfAddMulti(int s, char *interface, char *addr)
175 {
176 	struct ifreq	ifr;
177 	int		fd;
178 
179 	strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name) - 1);
180 	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0;
181 
182 	ifr.ifr_addr.sa_family = AF_UNSPEC;
183 	bcopy(addr, ifr.ifr_addr.sa_data, 6);
184 
185 	/*
186 	 * open a socket, temporarily, to use for SIOC* ioctls
187 	 */
188 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
189 		syslog(LOG_ERR, "pfAddMulti: socket: %m");
190 		return (-1);
191 	}
192 	if (ioctl(fd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
193 		syslog(LOG_ERR, "pfAddMulti: SIOCADDMULTI: %m");
194 		close(fd);
195 		return (-1);
196 	}
197 	close(fd);
198 
199 	return (0);
200 }
201 
202 /*
203  * Delete a Multicast address from the interface
204  */
205 int
206 pfDelMulti(int s, char *interface, char *addr)
207 {
208 	struct ifreq	ifr;
209 	int		fd;
210 
211 	strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) - 1);
212 	ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
213 
214 	ifr.ifr_addr.sa_family = AF_UNSPEC;
215 	bcopy(addr, ifr.ifr_addr.sa_data, 6);
216 
217 	/*
218 	 * open a socket, temporarily, to use for SIOC* ioctls
219 	 *
220 	 */
221 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
222 		syslog(LOG_ERR, "pfDelMulti: socket: %m");
223 		return (-1);
224 	}
225 	if (ioctl(fd, SIOCDELMULTI, (caddr_t)&ifr) < 0) {
226 		syslog(LOG_ERR, "pfAddMulti: SIOCDELMULTI: %m");
227 		close(fd);
228 		return (-1);
229 	}
230 	close(fd);
231 
232 	return (0);
233 }
234 
235 /*
236  * read a packet
237  */
238 int
239 pfRead(int fd, u_char *buf, int len)
240 {
241 	return (read(fd, buf, len));
242 }
243 
244 /*
245  * write a packet
246  */
247 int
248 pfWrite(int fd, u_char *buf, int len, int trans)
249 {
250 	struct iovec	iov[2];
251 
252 	/* XXX */
253 	switch (trans) {
254 	case TRANS_8023:
255 		iov[0].iov_base = buf;
256 		iov[0].iov_len = 22;
257 		iov[1].iov_base = buf + 22;
258 		iov[1].iov_len = len - 22;
259 		break;
260 	default:
261 		iov[0].iov_base = buf;
262 		iov[0].iov_len = 14;
263 		iov[1].iov_base = buf + 14;
264 		iov[1].iov_len = len - 14;
265 		break;
266 	}
267 
268 	if (writev(fd, iov, 2) == len)
269 		return (len);
270 
271 	return (-1);
272 }
273 
274