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