xref: /netbsd-src/usr.sbin/mopd/common/pf.c (revision cdd21bd307854e72bdd5f364023525b60c7c4218)
1*cdd21bd3Schristos /*	$NetBSD: pf.c,v 1.13 2016/06/08 01:11:49 christos Exp $	*/
2fcab4c33Sthorpej 
3ed137f7cScjs /*
4ed137f7cScjs  * Copyright (c) 1993-95 Mats O Jansson.  All rights reserved.
5ed137f7cScjs  * Copyright (c) 1990 The Regents of the University of California.
6ed137f7cScjs  * All rights reserved.
7ed137f7cScjs  *
8ed137f7cScjs  * This code is partly derived from rarpd.
9ed137f7cScjs  *
10ed137f7cScjs  * Redistribution and use in source and binary forms, with or without
11ed137f7cScjs  * modification, are permitted provided that the following conditions
12ed137f7cScjs  * are met:
13ed137f7cScjs  * 1. Redistributions of source code must retain the above copyright
14ed137f7cScjs  *    notice, this list of conditions and the following disclaimer.
15ed137f7cScjs  * 2. Redistributions in binary form must reproduce the above copyright
16ed137f7cScjs  *    notice, this list of conditions and the following disclaimer in the
17ed137f7cScjs  *    documentation and/or other materials provided with the distribution.
1807ce4063Ssnj  * 3. The name of the author may not be used to endorse or promote products
19ed137f7cScjs  *    derived from this software without specific prior written permission.
20ed137f7cScjs  *
21ed137f7cScjs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22ed137f7cScjs  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23ed137f7cScjs  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24ed137f7cScjs  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25ed137f7cScjs  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26ed137f7cScjs  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27ed137f7cScjs  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28ed137f7cScjs  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29ed137f7cScjs  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30ed137f7cScjs  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31ed137f7cScjs  */
32ed137f7cScjs 
33*cdd21bd3Schristos #include "port.h"
3407ed8910Slukem #ifndef lint
35*cdd21bd3Schristos __RCSID("$NetBSD: pf.c,v 1.13 2016/06/08 01:11:49 christos Exp $");
36ed137f7cScjs #endif
37ed137f7cScjs 
3807ed8910Slukem #include "os.h"
3907ed8910Slukem 
40c438716dSchristos #include <paths.h>
41ed137f7cScjs #include <sys/uio.h>
42ed137f7cScjs #include <net/bpf.h>
43ed137f7cScjs 
4407ed8910Slukem #include "mopdef.h"
4507ed8910Slukem #include "pf.h"
4610dd0ebeSchristos #include "log.h"
47ed137f7cScjs 
48ed137f7cScjs /*
49ed137f7cScjs  * Variables
50ed137f7cScjs  */
51ed137f7cScjs 
52ed137f7cScjs extern int promisc;
53ed137f7cScjs 
54ed137f7cScjs /*
55ed137f7cScjs  * Return information to device.c how to open device.
56ed137f7cScjs  * In this case the driver can handle both Ethernet type II and
57ed137f7cScjs  * IEEE 802.3 frames (SNAP) in a single pfOpen.
58ed137f7cScjs  */
59ed137f7cScjs 
60ed137f7cScjs int
pfTrans(const char * interface)6186b474faSdrochner pfTrans(const char *interface)
62ed137f7cScjs {
63ed137f7cScjs 	return TRANS_ETHER+TRANS_8023+TRANS_AND;
64ed137f7cScjs }
65ed137f7cScjs 
66ed137f7cScjs /*
67ed137f7cScjs  * Open and initialize packet filter.
68ed137f7cScjs  */
69ed137f7cScjs 
70ed137f7cScjs int
pfInit(const char * interface,int mode,u_short protocol,int typ)7186b474faSdrochner pfInit(const char *interface, int mode, u_short protocol, int typ)
72ed137f7cScjs {
73ed137f7cScjs 	int	fd;
74ed137f7cScjs 	struct ifreq ifr;
75ed137f7cScjs 	u_int	dlt;
76ed137f7cScjs 	int	immediate;
77221fa572Sdarrenr 	u_int	bufsize;
78c438716dSchristos 	const char *device = _PATH_BPF;
79ed137f7cScjs 
80ed137f7cScjs 	static struct bpf_insn insns[] = {
81ed137f7cScjs 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12),
82ed137f7cScjs 		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 4, 0),
83ed137f7cScjs 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20),
84ed137f7cScjs 		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 0, 3),
85ed137f7cScjs 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 14),
86ed137f7cScjs 		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xaaaa, 0, 1),
87ed137f7cScjs 		BPF_STMT(BPF_RET | BPF_K, 1520),
88ed137f7cScjs 		BPF_STMT(BPF_RET | BPF_K, 0),
89ed137f7cScjs 	};
90ed137f7cScjs 	static struct bpf_program filter = {
91ed137f7cScjs 		sizeof insns / sizeof(insns[0]),
92ed137f7cScjs 		insns
93ed137f7cScjs 	};
94ed137f7cScjs 
95ed137f7cScjs 	fd = open(device, mode);
96ed137f7cScjs 	if (fd < 0) {
9710dd0ebeSchristos       		mopLogWarn("pfInit: open %s", device);
98ed137f7cScjs 		return(-1);
99ed137f7cScjs 	}
100ed137f7cScjs 
101ed137f7cScjs 	/* Set immediate mode so packets are processed as they arrive. */
102ed137f7cScjs 	immediate = 1;
103ed137f7cScjs 	if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
10410dd0ebeSchristos       		mopLogWarn("pfInit: BIOCIMMEDIATE");
105ed137f7cScjs 		return(-1);
106ed137f7cScjs 	}
107221fa572Sdarrenr 	bufsize = 32768;
108221fa572Sdarrenr 	if (ioctl(fd, BIOCSBLEN, &bufsize) < 0) {
109221fa572Sdarrenr       		mopLogWarn("pfInit: BIOCSBLEN(%d)", bufsize);
110221fa572Sdarrenr 	}
111ed137f7cScjs 	(void) strncpy(ifr.ifr_name, interface, sizeof ifr.ifr_name);
112ed137f7cScjs 	if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) {
11310dd0ebeSchristos       		mopLogWarn("pfInit: BIOCSETIF");
114ed137f7cScjs 		return(-1);
115ed137f7cScjs 	}
116ed137f7cScjs 	/* Check that the data link layer is an Ethernet; this code won't work
117ed137f7cScjs 	 * with anything else. */
118ed137f7cScjs 	if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) {
11910dd0ebeSchristos       		mopLogWarn("pfInit: BIOCGDLT");
120ed137f7cScjs 		return(-1);
121ed137f7cScjs 	}
122ed137f7cScjs 	if (dlt != DLT_EN10MB) {
12310dd0ebeSchristos       		mopLogWarnX("pfInit: %s is not ethernet", device);
124ed137f7cScjs 		return(-1);
125ed137f7cScjs 	}
126ed137f7cScjs 	if (promisc) {
127ed137f7cScjs 		/* Set promiscuous mode. */
128ed137f7cScjs 		if (ioctl(fd, BIOCPROMISC, (caddr_t)0) < 0) {
12910dd0ebeSchristos       			mopLogWarn("pfInit: BIOCPROMISC");
130ed137f7cScjs 			return(-1);
131ed137f7cScjs 		}
132ed137f7cScjs 	}
133ed137f7cScjs 	/* Set filter program. */
134ed137f7cScjs 	insns[1].k = protocol;
135ed137f7cScjs 	insns[3].k = protocol;
136ed137f7cScjs 
137ed137f7cScjs 	if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) {
13810dd0ebeSchristos       		mopLogWarn("pfInit: BIOCSETF");
139ed137f7cScjs 		return(-1);
140ed137f7cScjs 	}
141ed137f7cScjs 	return(fd);
142ed137f7cScjs }
143ed137f7cScjs 
144ed137f7cScjs /*
145ed137f7cScjs  * Add a Multicast address to the interface
146ed137f7cScjs  */
147ed137f7cScjs 
148ed137f7cScjs int
pfAddMulti(int s,const char * interface,const char * addr)14986b474faSdrochner pfAddMulti(int s, const char *interface, const char *addr)
150ed137f7cScjs {
151ed137f7cScjs 	struct ifreq ifr;
152ed137f7cScjs 	int	fd;
153ed137f7cScjs 
154ea854da6Sitojun 	strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
155ed137f7cScjs 
156ed137f7cScjs 	ifr.ifr_addr.sa_family = AF_UNSPEC;
15707ed8910Slukem 	memmove(ifr.ifr_addr.sa_data, addr, 6);
158ed137f7cScjs 
159ed137f7cScjs 	/*
160ed137f7cScjs 	 * open a socket, temporarily, to use for SIOC* ioctls
161ed137f7cScjs 	 *
162ed137f7cScjs 	 */
163ed137f7cScjs 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
16410dd0ebeSchristos 		mopLogWarn("pfAddMulti: socket");
165ed137f7cScjs 		return(-1);
166ed137f7cScjs 	}
167ed137f7cScjs 	if (ioctl(fd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
16810dd0ebeSchristos 		mopLogWarn("pfAddMulti: SIOCADDMULTI");
169ed137f7cScjs 		close(fd);
170ed137f7cScjs 		return(-1);
171ed137f7cScjs 	}
172ed137f7cScjs 	close(fd);
173ed137f7cScjs 
174ed137f7cScjs 	return(0);
175ed137f7cScjs }
176ed137f7cScjs 
177ed137f7cScjs /*
178ed137f7cScjs  * Delete a Multicast address from the interface
179ed137f7cScjs  */
180ed137f7cScjs 
181ed137f7cScjs int
pfDelMulti(int s,const char * interface,const char * addr)18286b474faSdrochner pfDelMulti(int s, const char *interface, const char *addr)
183ed137f7cScjs {
184ed137f7cScjs 	struct ifreq ifr;
185ed137f7cScjs 	int	fd;
186ed137f7cScjs 
187ea854da6Sitojun 	strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
188ed137f7cScjs 
189ed137f7cScjs 	ifr.ifr_addr.sa_family = AF_UNSPEC;
19007ed8910Slukem 	memmove(ifr.ifr_addr.sa_data, addr, 6);
191ed137f7cScjs 
192ed137f7cScjs 	/*
193ed137f7cScjs 	 * open a socket, temporarily, to use for SIOC* ioctls
194ed137f7cScjs 	 *
195ed137f7cScjs 	 */
196ed137f7cScjs 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
19710dd0ebeSchristos 		mopLogWarn("pfDelMulti: socket");
198ed137f7cScjs 		return(-1);
199ed137f7cScjs 	}
200ed137f7cScjs 	if (ioctl(fd, SIOCDELMULTI, (caddr_t)&ifr) < 0) {
20110dd0ebeSchristos 		mopLogWarn("pfAddMulti: SIOCDELMULTI");
202ed137f7cScjs 		close(fd);
203ed137f7cScjs 		return(-1);
204ed137f7cScjs 	}
205ed137f7cScjs 	close(fd);
206ed137f7cScjs 
207ed137f7cScjs 	return(0);
208ed137f7cScjs }
209ed137f7cScjs 
210ed137f7cScjs /*
211ed137f7cScjs  * read a packet
212ed137f7cScjs  */
213ed137f7cScjs 
214ed137f7cScjs int
pfRead(int fd,u_char * buf,int len)21586b474faSdrochner pfRead(int fd, u_char *buf, int len)
216ed137f7cScjs {
217ed137f7cScjs 	return(read(fd, buf, len));
218ed137f7cScjs }
219ed137f7cScjs 
220ed137f7cScjs /*
221ed137f7cScjs  * write a packet
222ed137f7cScjs  */
223ed137f7cScjs 
224ed137f7cScjs int
pfWrite(int fd,const u_char * buf,int len,int trans)22586b474faSdrochner pfWrite(int fd, const u_char *buf, int len, int trans)
226ed137f7cScjs {
227ed137f7cScjs 
228ed137f7cScjs 	struct iovec iov[2];
229ed137f7cScjs 
230ed137f7cScjs 	switch (trans) {
231ed137f7cScjs 	case TRANS_8023:
23286b474faSdrochner 		iov[0].iov_base = (caddr_t)__UNCONST(buf);
233ed137f7cScjs 		iov[0].iov_len = 22;
23486b474faSdrochner 		iov[1].iov_base = (caddr_t)__UNCONST(buf+22);
235ed137f7cScjs 		iov[1].iov_len = len-22;
236ed137f7cScjs 		break;
237ed137f7cScjs 	default:
23886b474faSdrochner 		iov[0].iov_base = (caddr_t)__UNCONST(buf);
239ed137f7cScjs 		iov[0].iov_len = 14;
24086b474faSdrochner 		iov[1].iov_base = (caddr_t)__UNCONST(buf+14);
241ed137f7cScjs 		iov[1].iov_len = len-14;
242ed137f7cScjs 		break;
243ed137f7cScjs 	}
244ed137f7cScjs 
245ed137f7cScjs 	if (writev(fd, iov, 2) == len)
246ed137f7cScjs 		return(len);
247ed137f7cScjs 
248ed137f7cScjs 	return(-1);
249ed137f7cScjs }
250ed137f7cScjs 
251