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