1 /* $OpenBSD: pf-snit.c,v 1.3 2000/02/20 17:45:34 bitblt Exp $ */ 2 3 /* 4 * Copyright (c) 1993-96 Mats O Jansson. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Mats O Jansson. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef LINT 33 static char rcsid[] = "$OpenBSD: pf-snit.c,v 1.3 2000/02/20 17:45:34 bitblt Exp $"; 34 #endif 35 36 #include <stdio.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 #define DEV_NIT "/dev/nit" 46 #include <net/nit.h> 47 #include <net/nit_if.h> 48 #include <net/nit_pf.h> 49 #include <net/nit_buf.h> 50 #include <net/packetfilt.h> 51 #include <stropts.h> 52 53 #include <netinet/in.h> 54 #include <netinet/if_ether.h> 55 56 #include <netdb.h> 57 #include <ctype.h> 58 #include <syslog.h> 59 60 #include "common/mopdef.h" 61 62 /* 63 * Variables 64 */ 65 66 /* struct ifreq ifr; */ 67 extern int errno; 68 extern int promisc; 69 70 /* 71 * Return information to device.c how to open device. 72 * In this case the driver can handle both Ethernet type II and 73 * IEEE 802.3 frames (SNAP) in a single pfOpen. 74 */ 75 76 int 77 pfTrans(interface) 78 char *interface; 79 { 80 return TRANS_ETHER+TRANS_8023+TRANS_AND; 81 } 82 83 /* 84 * Open and initialize packet filter. 85 */ 86 87 int 88 pfInit(interface, mode, protocol, trans) 89 char *interface; 90 u_short protocol; 91 int trans, mode; 92 { 93 int fd; 94 int ioarg; 95 char device[64]; 96 unsigned long if_flags; 97 98 struct ifreq ifr; 99 struct strioctl si; 100 101 /* get clone */ 102 if ((fd = open(DEV_NIT, mode)) < 0) { 103 syslog(LOG_ERR,"pfInit: open nit %m"); 104 return(-1); 105 } 106 107 /* 108 * set filter for protocol 109 */ 110 111 if (setup_pf(fd, protocol, trans) < 0) 112 return(-1); 113 114 /* 115 * set options, bind to underlying interface 116 */ 117 118 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); 119 120 /* bind */ 121 si.ic_cmd = NIOCBIND; /* bind to underlying interface */ 122 si.ic_timout = 10; 123 si.ic_len = sizeof(ifr); 124 si.ic_dp = (caddr_t)𝔦 125 if (ioctl(fd, I_STR, (caddr_t)&si) < 0) { 126 syslog(LOG_ERR,"pfinit: I_STR %m"); 127 return(-1); 128 } 129 130 if (promisc) { 131 if_flags = NI_PROMISC; 132 si.ic_cmd = NIOCSFLAGS; 133 si.ic_timout = 10; 134 si.ic_len = sizeof(if_flags); 135 si.ic_dp = (caddr_t)&if_flags; 136 if (ioctl(fd, I_STR, (caddr_t)&si) < 0) { 137 syslog(LOG_ERR,"pfInit: I_STR (promisc) %m"); 138 return(-1); 139 } 140 } 141 142 /* set up messages */ 143 if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) { /* want messages */ 144 syslog(LOG_ERR,"pfInit: I_SRDOPT %m"); 145 return(-1); 146 } 147 148 /* flush read queue */ 149 if (ioctl(fd, I_FLUSH, (char *)FLUSHR) < 0) { 150 syslog(LOG_ERR,"pfInit: I_FLUSH %m"); 151 return(-1); 152 } 153 154 return(fd); 155 } 156 157 /* 158 * establish protocol filter 159 */ 160 161 int 162 setup_pf(s, prot, trans) 163 int s, trans; 164 u_short prot; 165 { 166 int ioarg; 167 u_short offset; 168 169 struct packetfilt pf; 170 register u_short *fwp = pf.Pf_Filter; 171 struct strioctl si; 172 173 #define s_offset(structp, element) (&(((structp)0)->element)) 174 175 bzero(&pf, sizeof(pf)); 176 pf.Pf_Priority = 128; 177 178 offset = ((int)s_offset(struct ether_header *, ether_type))/sizeof(u_short); 179 *fwp++ = ENF_PUSHWORD + offset; /* Check Ethernet type II */ 180 *fwp++ = ENF_PUSHLIT | ENF_EQ; /* protocol prot */ 181 *fwp++ = htons(prot); 182 *fwp++ = ENF_PUSHWORD + offset + 4; /* Check 802.3 protocol prot */ 183 *fwp++ = ENF_PUSHLIT | ENF_EQ; 184 *fwp++ = htons(prot); 185 *fwp++ = ENF_PUSHWORD + offset + 1; /* Check for SSAP and DSAP */ 186 *fwp++ = ENF_PUSHLIT | ENF_EQ; 187 *fwp++ = htons(0xaaaa); 188 *fwp++ = ENF_AND; 189 *fwp++ = ENF_OR; 190 pf.Pf_FilterLen = 11; 191 192 si.ic_cmd = NIOCSETF; 193 si.ic_timout = 10; 194 si.ic_len = sizeof(pf); 195 si.ic_dp = (char *)&pf; 196 if (ioctl(s, I_PUSH, "pf") < 0) { 197 syslog(LOG_ERR,"setup_pf: I_PUSH %m"); 198 return(-1); 199 } 200 if (ioctl(s, I_STR, (char *)&si) < 0) { 201 syslog(LOG_ERR,"setup_pf: I_STR %m"); 202 return(-1); 203 } 204 205 return(0); 206 } 207 208 /* 209 * Get the interface ethernet address 210 */ 211 212 int 213 pfEthAddr(fd, addr) 214 int fd; 215 u_char *addr; 216 { 217 struct ifreq ifr; 218 struct sockaddr *sa; 219 220 if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) { 221 syslog(LOG_ERR,"pfEthAddr: SIOCGIFADDR %m"); 222 return(-1); 223 } 224 sa = (struct sockaddr *)ifr.ifr_data; 225 bcopy((char *)sa->sa_data, (char *)addr, 6); 226 227 return(0); 228 } 229 230 /* 231 * Add a Multicast address to the interface 232 */ 233 234 int 235 pfAddMulti(s, interface, addr) 236 int s; 237 char *interface, *addr; 238 { 239 struct ifreq ifr; 240 int fd; 241 242 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) -1); 243 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0; 244 245 ifr.ifr_addr.sa_family = AF_UNSPEC; 246 bcopy(addr, ifr.ifr_addr.sa_data, 6); 247 248 /* 249 * open a socket, temporarily, to use for SIOC* ioctls 250 */ 251 252 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 253 syslog(LOG_ERR,"pfAddMulti: socket() %m"); 254 return(-1); 255 } 256 if (ioctl(fd, SIOCADDMULTI, (caddr_t)&ifr) < 0) { 257 syslog(LOG_ERR,"pfAddMulti: SIOCADDMULTI %m"); 258 close(fd); 259 return(-1); 260 } 261 close(fd); 262 263 return(0); 264 } 265 266 /* 267 * delete a multicast address from the interface 268 */ 269 270 int 271 pfDelMulti(s, interface, addr) 272 int s; 273 char *interface, *addr; 274 { 275 struct ifreq ifr; 276 int fd; 277 278 strncpy(ifr.ifr_name, interface, sizeof (ifr.ifr_name) -1); 279 ifr.ifr_name[sizeof(ifr.ifr_name)] = 0; 280 281 ifr.ifr_addr.sa_family = AF_UNSPEC; 282 bcopy(addr, ifr.ifr_addr.sa_data, 6); 283 284 /* 285 * open a socket, temporarily, to use for SIOC* ioctls 286 * 287 */ 288 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 289 syslog(LOG_ERR,"pfDelMulti: socket() %m"); 290 return(-1); 291 } 292 293 if (ioctl(fd, SIOCDELMULTI, (caddr_t)&ifr) < 0) { 294 syslog(LOG_ERR,"pfDelMulti: SIOCDELMULTI %m"); 295 close(fd); 296 return(-1); 297 } 298 close(fd); 299 300 return(0); 301 } 302 303 /* 304 * read a packet 305 */ 306 307 int 308 pfRead(fd, buf, len) 309 int fd, len; 310 u_char *buf; 311 { 312 return(read(fd, buf, len)); 313 } 314 315 /* 316 * write a packet 317 */ 318 319 int 320 pfWrite(fd, buf, len, trans) 321 int fd, len, trans; 322 u_char *buf; 323 { 324 325 struct sockaddr sa; 326 struct strbuf pbuf, dbuf; 327 328 sa.sa_family = AF_UNSPEC; 329 bcopy(buf, sa.sa_data, sizeof(sa.sa_data)); 330 331 switch (trans) { 332 default: 333 pbuf.len = sizeof(struct sockaddr); 334 pbuf.buf = (char *) &sa; 335 dbuf.len = len-14; 336 dbuf.buf = (char *)buf+14; 337 break; 338 } 339 340 if (putmsg(fd, &pbuf, &dbuf, 0) == 0) 341 return(len); 342 343 return(-1); 344 } 345