1 |
|
|
/* $OpenBSD: pf.c,v 1.17 2017/04/19 05:36:13 natano 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 |
|
|
#include <stdio.h> |
32 |
|
|
#include <unistd.h> |
33 |
|
|
#include <sys/types.h> |
34 |
|
|
#include <sys/time.h> |
35 |
|
|
#include <sys/ioctl.h> |
36 |
|
|
#include <sys/file.h> |
37 |
|
|
#include <sys/socket.h> |
38 |
|
|
#include <sys/uio.h> |
39 |
|
|
#include <net/if.h> |
40 |
|
|
|
41 |
|
|
#include <net/bpf.h> |
42 |
|
|
|
43 |
|
|
#include <netinet/in.h> |
44 |
|
|
#include <netinet/if_ether.h> |
45 |
|
|
|
46 |
|
|
#include <netdb.h> |
47 |
|
|
#include <ctype.h> |
48 |
|
|
#include <string.h> |
49 |
|
|
#include <err.h> |
50 |
|
|
#include <errno.h> |
51 |
|
|
|
52 |
|
|
#include <syslog.h> |
53 |
|
|
|
54 |
|
|
#include "common/mopdef.h" |
55 |
|
|
|
56 |
|
|
/* |
57 |
|
|
* Variables |
58 |
|
|
*/ |
59 |
|
|
|
60 |
|
|
extern int promisc; |
61 |
|
|
|
62 |
|
|
/* |
63 |
|
|
* Return information to device.c how to open device. |
64 |
|
|
* In this case the driver can handle both Ethernet type II and |
65 |
|
|
* IEEE 802.3 frames (SNAP) in a single pfOpen. |
66 |
|
|
*/ |
67 |
|
|
/* ARGSUSED */ |
68 |
|
|
int |
69 |
|
|
pfTrans(char *interface) |
70 |
|
|
{ |
71 |
|
|
return (TRANS_ETHER + TRANS_8023 + TRANS_AND); |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
/* |
75 |
|
|
* Open and initialize packet filter. |
76 |
|
|
*/ |
77 |
|
|
/* ARGSUSED */ |
78 |
|
|
int |
79 |
|
|
pfInit(char *interface, int mode, u_short protocol, int typ) |
80 |
|
|
{ |
81 |
|
|
int fd; |
82 |
|
|
struct ifreq ifr; |
83 |
|
|
u_int dlt; |
84 |
|
|
int immediate; |
85 |
|
|
|
86 |
|
|
static struct bpf_insn insns[] = { |
87 |
|
|
BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12), |
88 |
|
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 4, 0), |
89 |
|
|
BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20), |
90 |
|
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x4711, 0, 3), |
91 |
|
|
BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 14), |
92 |
|
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xaaaa, 0, 1), |
93 |
|
|
BPF_STMT(BPF_RET | BPF_K, 1520), |
94 |
|
|
BPF_STMT(BPF_RET | BPF_K, 0), |
95 |
|
|
}; |
96 |
|
|
static struct bpf_program filter = { |
97 |
|
|
sizeof insns / sizeof(insns[0]), |
98 |
|
|
insns |
99 |
|
|
}; |
100 |
|
|
|
101 |
|
|
if ((fd = open("/dev/bpf", mode)) == -1) { |
102 |
|
|
syslog(LOG_ERR,"pfInit: open bpf %m"); |
103 |
|
|
return (-1); |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
/* Set immediate mode so packets are processed as they arrive. */ |
107 |
|
|
immediate = 1; |
108 |
|
|
if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) { |
109 |
|
|
syslog(LOG_ERR,"pfInit: BIOCIMMEDIATE: %m"); |
110 |
|
|
return (-1); |
111 |
|
|
} |
112 |
|
|
strncpy(ifr.ifr_name, interface, sizeof ifr.ifr_name); |
113 |
|
|
if (ioctl(fd, BIOCSETIF, &ifr) < 0) { |
114 |
|
|
syslog(LOG_ERR,"pfInit: BIOCSETIF: %m"); |
115 |
|
|
return (-1); |
116 |
|
|
} |
117 |
|
|
/* Check that the data link layer is an Ethernet; this code won't work |
118 |
|
|
* with anything else. */ |
119 |
|
|
if (ioctl(fd, BIOCGDLT, &dlt) < 0) { |
120 |
|
|
syslog(LOG_ERR,"pfInit: BIOCGDLT: %m"); |
121 |
|
|
return (-1); |
122 |
|
|
} |
123 |
|
|
if (dlt != DLT_EN10MB) { |
124 |
|
|
syslog(LOG_ERR,"pfInit: %s is not ethernet", interface); |
125 |
|
|
return (-1); |
126 |
|
|
} |
127 |
|
|
if (promisc) |
128 |
|
|
/* Set promiscuous mode. */ |
129 |
|
|
if (ioctl(fd, BIOCPROMISC, 0) < 0) { |
130 |
|
|
syslog(LOG_ERR,"pfInit: BIOCPROMISC: %m"); |
131 |
|
|
return (-1); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
/* Set filter program. */ |
135 |
|
|
insns[1].k = protocol; |
136 |
|
|
insns[3].k = protocol; |
137 |
|
|
|
138 |
|
|
if (ioctl(fd, BIOCSETF, &filter) < 0) { |
139 |
|
|
syslog(LOG_ERR,"pfInit: BIOCSETF: %m"); |
140 |
|
|
return (-1); |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
/* XXX set the same write filter (for protocol only) */ |
144 |
|
|
if (ioctl(fd, BIOCSETWF, &filter) < 0) { |
145 |
|
|
syslog(LOG_ERR,"pfInit: BIOCSETWF: %m"); |
146 |
|
|
return (-1); |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
/* Lock the interface to prevent further changes */ |
150 |
|
|
if (ioctl(fd, BIOCLOCK) < 0) { |
151 |
|
|
syslog(LOG_ERR,"pfInit: BIOCLOCK: %m"); |
152 |
|
|
return (-1); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
return (fd); |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
/* |
159 |
|
|
* Add a Multicast address to the interface |
160 |
|
|
*/ |
161 |
|
|
/* ARGSUSED */ |
162 |
|
|
int |
163 |
|
|
pfAddMulti(int s, char *interface, char *addr) |
164 |
|
|
{ |
165 |
|
|
struct ifreq ifr; |
166 |
|
|
int fd; |
167 |
|
|
|
168 |
|
|
strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name) - 1); |
169 |
|
|
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0; |
170 |
|
|
|
171 |
|
|
ifr.ifr_addr.sa_family = AF_UNSPEC; |
172 |
|
|
bcopy(addr, ifr.ifr_addr.sa_data, 6); |
173 |
|
|
|
174 |
|
|
/* |
175 |
|
|
* open a socket, temporarily, to use for SIOC* ioctls |
176 |
|
|
*/ |
177 |
|
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
178 |
|
|
syslog(LOG_ERR, "pfAddMulti: socket: %m"); |
179 |
|
|
return (-1); |
180 |
|
|
} |
181 |
|
|
if (ioctl(fd, SIOCADDMULTI, &ifr) < 0) { |
182 |
|
|
syslog(LOG_ERR, "pfAddMulti: SIOCADDMULTI: %m"); |
183 |
|
|
close(fd); |
184 |
|
|
return (-1); |
185 |
|
|
} |
186 |
|
|
close(fd); |
187 |
|
|
|
188 |
|
|
return (0); |
189 |
|
|
} |
190 |
|
|
|
191 |
|
|
/* |
192 |
|
|
* Delete a Multicast address from the interface |
193 |
|
|
*/ |
194 |
|
|
/* ARGSUSED */ |
195 |
|
|
int |
196 |
|
|
pfDelMulti(int s, char *interface, char *addr) |
197 |
|
|
{ |
198 |
|
|
struct ifreq ifr; |
199 |
|
|
int fd; |
200 |
|
|
|
201 |
|
|
strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) - 1); |
202 |
|
|
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; |
203 |
|
|
|
204 |
|
|
ifr.ifr_addr.sa_family = AF_UNSPEC; |
205 |
|
|
bcopy(addr, ifr.ifr_addr.sa_data, 6); |
206 |
|
|
|
207 |
|
|
/* |
208 |
|
|
* open a socket, temporarily, to use for SIOC* ioctls |
209 |
|
|
* |
210 |
|
|
*/ |
211 |
|
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
212 |
|
|
syslog(LOG_ERR, "pfDelMulti: socket: %m"); |
213 |
|
|
return (-1); |
214 |
|
|
} |
215 |
|
|
if (ioctl(fd, SIOCDELMULTI, &ifr) < 0) { |
216 |
|
|
syslog(LOG_ERR, "pfAddMulti: SIOCDELMULTI: %m"); |
217 |
|
|
close(fd); |
218 |
|
|
return (-1); |
219 |
|
|
} |
220 |
|
|
close(fd); |
221 |
|
|
|
222 |
|
|
return (0); |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
/* |
226 |
|
|
* read a packet |
227 |
|
|
*/ |
228 |
|
|
int |
229 |
|
|
pfRead(int fd, u_char *buf, int len) |
230 |
|
|
{ |
231 |
|
|
return (read(fd, buf, len)); |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
/* |
235 |
|
|
* write a packet |
236 |
|
|
*/ |
237 |
|
|
int |
238 |
|
|
pfWrite(int fd, u_char *buf, int len, int trans) |
239 |
|
|
{ |
240 |
|
|
struct iovec iov[2]; |
241 |
|
|
|
242 |
|
|
/* XXX */ |
243 |
|
|
switch (trans) { |
244 |
|
|
case TRANS_8023: |
245 |
|
|
iov[0].iov_base = buf; |
246 |
|
|
iov[0].iov_len = 22; |
247 |
|
|
iov[1].iov_base = buf + 22; |
248 |
|
|
iov[1].iov_len = len - 22; |
249 |
|
|
break; |
250 |
|
|
default: |
251 |
|
|
iov[0].iov_base = buf; |
252 |
|
|
iov[0].iov_len = 14; |
253 |
|
|
iov[1].iov_base = buf + 14; |
254 |
|
|
iov[1].iov_len = len - 14; |
255 |
|
|
break; |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
if (writev(fd, iov, 2) == len) |
259 |
|
|
return (len); |
260 |
|
|
|
261 |
|
|
return (-1); |
262 |
|
|
} |
263 |
|
|
|