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