1 /* $Id: ssp_pf.c,v 3.6 2009/11/27 01:39:40 fknobbe Exp $
2  *
3  * Copyright (c) 2003 Hector Paterno <apaterno@dsnsecurity.com>
4  * Copyright (c) 2004-2008 Olaf Schreck <chakl@syscall.de>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *
29  * ssp_pf.c
30  *
31  * Purpose:
32  *
33  * This SnortSam plugin is meant for dynamic (un)blocking on PF (OpenBSD) firewall,
34  * SnortSam will expire the blocks itself since PF does not have
35  * automatic time-out functionality.
36  *
37  * It Works on OpenBSD >= 3_3, and for FreeBSD >= 5.1.
38  * For newer *BSD versions use the PF2 plugin.
39  */
40 
41 #ifndef USE_SSP_PF
42 #if defined(OpenBSD) || defined(FreeBSD) || defined(NetBSD)
43 
44 #ifndef		__SSP_PF_C__
45 #define		__SSP_PF_C__
46 
47 #include "snortsam.h"
48 #include "ssp_pf.h"
49 
50 #include <sys/types.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <time.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
56 /* By pf */
57 #include <sys/ioctl.h>
58 #include <sys/fcntl.h>
59 #include <net/if.h>
60 #include <net/pfvar.h>
61 #include <sys/param.h>
62 #include <errno.h>
63 /* End */
64 
65 /* Defines should be done in ssp_pf.h */
66 
67 
68 /* Routine for opt parsing ( opt=value opt2=value2 etc. ) */
parse_opts(char * line,opt_s * opt,char * sep,char * int_sep,int nopt)69 int parse_opts(char *line, opt_s *opt, char *sep, char *int_sep, int nopt)
70 {
71    char *last;
72    char *last2;
73    char *pt;
74    char *pt2;
75    int fo=0;
76    int di=0;
77 
78    if((line==NULL) || (opt==NULL) || (sep==NULL) || (int_sep==NULL))
79      return -1;
80 
81    for(pt=strtok_r(line, sep, &last); pt; pt=strtok_r(NULL, sep, &last))
82      {
83 	for(pt2=strtok_r(pt, int_sep, &last2), fo=0; pt2; pt2=strtok_r(NULL, int_sep, &last2))
84 	  {
85 	     if(fo==0)
86 	       {
87 		  for(; fo<nopt; fo++)
88 		    {
89 		      if (strncmp(opt[fo].name, pt2, MAX_OPT_NAME)==0)
90 			 {
91 			    fo++;
92 			    di++;
93 			    break;
94 			 }
95 		    }
96 	       }
97 	     else
98 	       {
99 		  if(di)
100 		    if(opt[--fo].vt>0)
101 		      strncpy(opt[fo].v.value_s, pt2, MAX_OPT_VALUE);
102 		    else
103 		      opt[fo].v.value_d=atoi(pt2);
104 		  fo=0;
105 		  di=0;
106 	       }
107 	  }
108      }
109 
110    return;
111 }
112 
113 
114 /*
115  * This routine parses the pf statements in the config file.
116  * TODO: If the "auto" parameter is pased, initialize the main rule, anchor and rulesets/rules
117  */
118 void
PFParse(char * val,char * file,unsigned long line,DATALIST * plugindatalist)119 PFParse(char *val, char *file, unsigned long line, DATALIST * plugindatalist)
120 {
121    PFDATA         *pfp = NULL;
122    char           msg[STRBUFSIZE + 2];
123    opt_s          options[5]={
124 	{"auto",   0,  0},
125 	{"log",    0,  0},
126 	{"eth",    "", 1},
127 	{"anchor", "", 1},
128 	{"table",  "", 1}
129    };
130 
131    /* used for auto=1 */
132    int pfdev;
133    struct pfioc_rule rule;
134    struct pfioc_pooladdr paddr;
135    struct pfioc_table tablemain;
136    struct pfr_table table;
137 
138 
139 #ifdef FWSAMDEBUG
140    printf("Debug: [pf] Plugin Parsing...\n");
141 #endif
142 
143    if (*val)
144      {
145 	if(parse_opts(val, options, " \t", "=", (sizeof(options)/sizeof(opt_s)))<0)
146 	  {
147 	     snprintf(msg, sizeof(msg) - 1, "Error: [%s: %lu] invalid PF parameters !. PF Plugin disabled.", file, line);
148 	     logmessage(1, msg, "pf", 0);
149 	     plugindatalist->data=NULL;
150 	     return;
151 	  }
152 
153 	pfp = safemalloc(sizeof(PFDATA), "PFParse", "pfp");
154 	bzero(pfp, sizeof(PFDATA));
155 	plugindatalist->data = pfp;
156 
157 	/* Check Anchor */
158 	if(strlen(options[PF_OPT_ANCHOR].v.value_s)<1)
159 	  {
160 	     snprintf(msg, sizeof(msg) - 1, "Info: [%s: %lu] PF anchor name not defined, using \"snortsam\"", file, line );
161 	     logmessage(1, msg, "pf", 0);
162 	     safecopy(pfp->anchorname, "snortsam");	/* save anchorname */
163 	  }
164 	else
165 	  {
166 	     safecopy(pfp->anchorname, options[PF_OPT_ANCHOR].v.value_s);	/* save anchorname */
167 	  }
168 
169 	/* define the table (fixed cannot changed) */
170 	safecopy(pfp->tablename, "block");	/* save tablename */
171 
172 	   			       /* Check eth */
173 	if(strlen(options[PF_OPT_ETH].v.value_s)<1)
174 	  {
175 	     snprintf(msg, sizeof(msg) - 1, "Warning: [%s: %lu] PF ethernet name not defined, the IPs will be blocked on all interfaces !", file, line);
176 	     logmessage(1, msg, "pf", 0);
177 	  }
178 	else
179 	  {
180 	     safecopy(pfp->iface, options[PF_OPT_ETH].v.value_s);	/* save eth */
181 	  }
182 
183 	/* Save the log option */
184 	pfp->logopt = options[PF_OPT_LOG].v.value_d;
185 
186      }else
187      {
188 	snprintf(msg, sizeof(msg) - 1, "Error: [%s: %lu] PF defined without parameters! PF plugin disabled.", file, line);
189 	logmessage(1, msg, "pf", 0);
190 	free(pfp);
191 	plugindatalist->data=NULL;
192 	return;
193      }
194 
195    if(options[PF_OPT_AUTO].v.value_d)	       /* Create the anchor call rules, create the anchor, rulesets and tables */
196      {
197         if ((pfdev = open(PFDEV, PFPERM)) == -1)
198 	  {
199 	     snprintf(msg, sizeof(msg) - 1, "Error: Can't open %s device (auto=1), %s. PF plugin disabled.", PFDEV, strerror(errno));
200 	     logmessage(1, msg, "pf", 0);
201 	     free(pfp);
202 	     plugindatalist->data=NULL;
203 	     return;
204 	  }
205 
206 	/* Create the anchor call rule in main */
207 	bzero(&rule, sizeof(struct pfioc_rule));
208 	strncpy(rule.rule.ifname, pfp->iface, IFNAMSIZ);
209 	strncpy(rule.anchor_call, pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
210 
211 	rule.action = PF_CHANGE_GET_TICKET;
212 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
213 	  {
214 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 1 (auto=1) : %s. PF plugin disabled.", strerror(errno));
215 	     logmessage(1, msg, "pf", 0);
216 	     free(pfp);
217 	     plugindatalist->data=NULL;
218 	     return;
219 	  }
220 
221 	if(ioctl(pfdev, DIOCBEGINADDRS, &paddr)<0)
222 	  {
223 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCBEGINADDRS 2 (auto=1) : %s. PF plugin disabled.", strerror(errno));
224 	     logmessage(1, msg, "pf", 0);
225 	     free(pfp);
226 	     plugindatalist->data=NULL;
227 	     return;
228 	  }
229 
230 	rule.pool_ticket = paddr.ticket;
231 
232 	rule.action = PF_CHANGE_ADD_HEAD;
233 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
234 	  {
235 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 3 (auto=1) : %s. PF plugin disabled.", strerror(errno));
236 	     logmessage(1, msg, "pf", 0);
237 	     free(pfp);
238 	     plugindatalist->data=NULL;
239 	     return;
240 	  }
241 
242 	/* Create the Ruleset IN With It rule and table in the anchor */
243 	bzero(&tablemain, sizeof(struct pfioc_table));
244 	bzero(&table, sizeof(struct pfr_table));
245 
246  	 /* The table */
247 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
248 	strncpy(&(table.pfrt_name[0]), "blockin", PF_TABLE_NAME_SIZE-1);
249 	table.pfrt_flags = PFR_TFLAG_PERSIST;
250 	tablemain.pfrio_buffer = &table;
251 	tablemain.pfrio_size = 1;
252 	tablemain.pfrio_esize = sizeof(table);
253 
254 	if(ioctl(pfdev, DIOCRADDTABLES, &tablemain)<0)
255 	  {
256 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCRADDTABLES (auto=1) : %s. PF plugin disabled.", strerror(errno));
257 	     logmessage(1, msg, "pf", 0);
258 	     free(pfp);
259 	     plugindatalist->data=NULL;
260 	     return;
261 	  }
262 	 /* The rule (block in <logopt> from <tablename> to any */
263 	bzero(&rule, sizeof(struct pfioc_rule));
264 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
265 	strncpy(rule.anchor, pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
266 	rule.rule.action=PF_DROP;
267 	rule.rule.direction=PF_IN;
268 	rule.rule.quick=1;
269 	rule.rule.log=pfp->logopt;
270 	rule.rule.src.addr.type = PF_ADDR_TABLE;
271 
272 	strncpy(rule.rule.src.addr.v.tblname, "blockin", PF_TABLE_NAME_SIZE-1);
273 
274 	rule.action = PF_CHANGE_GET_TICKET;
275 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
276 	  {
277 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 4 (auto=1) : %s. PF plugin disabled.", strerror(errno));
278 	     logmessage(1, msg, "pf", 0);
279 	     free(pfp);
280 	     plugindatalist->data=NULL;
281 	     return;
282 	  }
283 
284 	if(ioctl(pfdev, DIOCBEGINADDRS, &paddr)<0)
285 	  {
286 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCBEGINADDRS (auto=1) : %s. PF plugin disabled.", strerror(errno));
287 	     logmessage(1, msg, "pf", 0);
288 	     free(pfp);
289 	     plugindatalist->data=NULL;
290 	     return;
291 	  }
292 
293 	rule.pool_ticket = paddr.ticket;
294 
295 	rule.action = PF_CHANGE_ADD_HEAD;
296 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
297 	  {
298 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 5 (auto=1) : %s. PF plugin disabled.", strerror(errno));
299 	     logmessage(1, msg, "pf", 0);
300 	     free(pfp);
301 	     plugindatalist->data=NULL;
302 	     return;
303 	  }
304 
305 	/* Create the Ruleset OUT With It rule and table in the anchor */
306 	bzero(&tablemain, sizeof(struct pfioc_table));
307 	bzero(&table, sizeof(struct pfr_table));
308 
309  	 /* The table */
310 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
311 	strncpy(&(table.pfrt_name[0]), "blockout", PF_TABLE_NAME_SIZE-1);
312 	table.pfrt_flags = PFR_TFLAG_PERSIST;
313 	tablemain.pfrio_buffer = &table;
314 	tablemain.pfrio_size = 1;
315 	tablemain.pfrio_esize = sizeof(table);
316 
317 	if(ioctl(pfdev, DIOCRADDTABLES, &tablemain)<0)
318 	  {
319 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCRADDTABLES (auto=1) : %s. PF plugin disabled.", strerror(errno));
320 	     logmessage(1, msg, "pf", 0);
321 	     free(pfp);
322 	     plugindatalist->data=NULL;
323 	     return;
324 	  }
325 	 /* The rule (block out <logopt> from any to <tablename>*/
326 	bzero(&rule, sizeof(struct pfioc_rule));
327 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
328 	strncpy(rule.anchor, pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
329 	rule.rule.action=PF_DROP;
330 	rule.rule.direction=PF_OUT;
331 	rule.rule.quick=1;
332 	rule.rule.log=pfp->logopt;
333 	rule.rule.dst.addr.type = PF_ADDR_TABLE;
334 
335 	strncpy(rule.rule.dst.addr.v.tblname, "blockout", PF_TABLE_NAME_SIZE-1);
336 
337 	rule.action = PF_CHANGE_GET_TICKET;
338 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
339 	  {
340 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 6 (auto=1) : %s. PF plugin disabled.", strerror(errno));
341 	     logmessage(1, msg, "pf", 0);
342 	     free(pfp);
343 	     plugindatalist->data=NULL;
344 	     return;
345 	  }
346 
347 	if(ioctl(pfdev, DIOCBEGINADDRS, &paddr)<0)
348 	  {
349 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCBEGINADDRS (auto=1) : %s. PF plugin disabled.", strerror(errno));
350 	     logmessage(1, msg, "pf", 0);
351 	     free(pfp);
352 	     plugindatalist->data=NULL;
353 	     return;
354 	  }
355 
356 	rule.pool_ticket = paddr.ticket;
357 
358 	rule.action = PF_CHANGE_ADD_HEAD;
359 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
360 	  {
361 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 7 (auto=1) : %s. PF plugin disabled.", strerror(errno));
362 	     logmessage(1, msg, "pf", 0);
363 	     free(pfp);
364 	     plugindatalist->data=NULL;
365 	     return;
366 	  }
367 
368 	/* Create the Ruleset INOUT With It rule and table in the anchor */
369 	bzero(&tablemain, sizeof(struct pfioc_table));
370 	bzero(&table, sizeof(struct pfr_table));
371 
372  	 /* The table */
373 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
374 	strncpy(&(table.pfrt_name[0]), "blockinout", PF_TABLE_NAME_SIZE-1);
375 	table.pfrt_flags = PFR_TFLAG_PERSIST;
376 	tablemain.pfrio_buffer = &table;
377 	tablemain.pfrio_size = 1;
378 	tablemain.pfrio_esize = sizeof(table);
379 
380 	if(ioctl(pfdev, DIOCRADDTABLES, &tablemain)<0)
381 	  {
382 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCRADDTABLES (auto=1) : %s. PF plugin disabled.", strerror(errno));
383 	     logmessage(1, msg, "pf", 0);
384 	     free(pfp);
385 	     plugindatalist->data=NULL;
386 	     return;
387 	  }
388 	 /* The rules (block in <logopt> from <tablename> to any, and, block out <logopt> from any to <tablename>*/
389 	  /* The IN */
390 	bzero(&rule, sizeof(struct pfioc_rule));
391 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
392 	strncpy(rule.anchor, pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
393 	rule.rule.action=PF_DROP;
394 	rule.rule.direction=PF_IN;
395 	rule.rule.quick=1;
396 	rule.rule.log=pfp->logopt;
397 	rule.rule.src.addr.type = PF_ADDR_TABLE;
398 
399 	strncpy(rule.rule.src.addr.v.tblname, "blockinout", PF_TABLE_NAME_SIZE-1);
400 
401 	rule.action = PF_CHANGE_GET_TICKET;
402 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
403 	  {
404 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 8 (auto=1) : %s. PF plugin disabled.", strerror(errno));
405 	     logmessage(1, msg, "pf", 0);
406 	     free(pfp);
407 	     plugindatalist->data=NULL;
408 	     return;
409 	  }
410 
411 	if(ioctl(pfdev, DIOCBEGINADDRS, &paddr)<0)
412 	  {
413 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCBEGINADDRS (auto=1) : %s. PF plugin disabled.", strerror(errno));
414 	     logmessage(1, msg, "pf", 0);
415 	     free(pfp);
416 	     plugindatalist->data=NULL;
417 	     return;
418 	  }
419 
420 	rule.pool_ticket = paddr.ticket;
421 
422 	rule.action = PF_CHANGE_ADD_HEAD;
423 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
424 	  {
425 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 9 (auto=1) : %s. PF plugin disabled.", strerror(errno));
426 	     logmessage(1, msg, "pf", 0);
427 	     free(pfp);
428 	     plugindatalist->data=NULL;
429 	     return;
430 	  }
431 
432 	  /* The OUT */
433 	bzero(&rule, sizeof(struct pfioc_rule));
434 	strncpy(&(table.pfrt_anchor[0]), pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
435 	strncpy(rule.anchor, pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
436 	rule.rule.action=PF_DROP;
437 	rule.rule.direction=PF_OUT;
438 	rule.rule.quick=1;
439 	rule.rule.log=pfp->logopt;
440 	rule.rule.dst.addr.type = PF_ADDR_TABLE;
441 
442 	strncpy(rule.rule.dst.addr.v.tblname, "blockinout", PF_TABLE_NAME_SIZE-1);
443 
444 	rule.action = PF_CHANGE_GET_TICKET;
445 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
446 	  {
447 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 10 (auto=1) : %s. PF plugin disabled.", strerror(errno));
448 	     logmessage(1, msg, "pf", 0);
449 	     free(pfp);
450 	     plugindatalist->data=NULL;
451 	     return;
452 	  }
453 
454 	if(ioctl(pfdev, DIOCBEGINADDRS, &paddr)<0)
455 	  {
456 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCBEGINADDRS (auto=1) : %s. PF plugin disabled.", strerror(errno));
457 	     logmessage(1, msg, "pf", 0);
458 	     free(pfp);
459 	     plugindatalist->data=NULL;
460 	     return;
461 	  }
462 
463 	rule.pool_ticket = paddr.ticket;
464 
465 	rule.action = PF_CHANGE_ADD_HEAD;
466 	if(ioctl(pfdev, DIOCCHANGERULE, &rule)<0)
467 	  {
468 	     snprintf(msg, sizeof(msg) - 1, "Error: DIOCCHANGERULE 11 (auto=1) : %s. PF plugin disabled.", strerror(errno));
469 	     logmessage(1, msg, "pf", 0);
470 	     free(pfp);
471 	     plugindatalist->data=NULL;
472 	     return;
473 	  }
474 
475 
476 	/* Start PF */
477 
478 	if(ioctl(pfdev, DIOCSTART, 0)<0)
479 	  {
480 	     if(errno==EEXIST)
481 	       {
482 		  snprintf(msg, sizeof(msg) - 1, "Info: PF Already Enabled (auto=1).");
483 		  logmessage(1, msg, "pf", 0);
484 	       }
485 	     else
486 	       {
487 		  snprintf(msg, sizeof(msg) - 1, "Error: Can't start PF (auto=1) : %s. PF plugin disabled.", strerror(errno));
488 		  logmessage(1, msg, "pf", 0);
489 		  free(pfp);
490 		  plugindatalist->data=NULL;
491 		  return;
492 	       }
493 
494 	  }
495 
496 
497 
498      }				       /* auto=1 */
499 
500 #ifdef FWSAMDEBUG
501    printf("Debug: [pf] Adding PF: \n");
502    printf("auto=%d\nlog=%d\neth=%s\n",options[PF_OPT_AUTO].v.value_d, pfp->logopt, pfp->iface);
503    printf("anchor=%s\ntable=%s\n",pfp->anchorname, pfp->tablename);
504 #endif
505 
506 }
507 
508 
509 /*
510  * BLOCK/UNBLOCK Routine
511  */
512 void
PFBlock(BLOCKINFO * bd,void * data,unsigned long qp)513 PFBlock(BLOCKINFO * bd, void * data,unsigned long qp)
514 {
515    PFDATA *pfp;
516    int    pfdev;
517    struct pfioc_table table;
518    struct pfr_addr pfr;
519    char   msg[STRBUFSIZE + 2];
520 #ifdef FWSAMDEBUG
521    pthread_t threadid=pthread_self();
522 #endif
523 
524    if(!data)
525      return;
526 
527    pfp=(PFDATA *)data;
528 
529 #ifdef FWSAMDEBUG
530    printf("Debug: [pf][%lx] Plugin Blocking...\n", threadid);
531 #endif
532 
533    if((pfdev=open(PFDEV, PFPERM))==-1)
534      {
535 	snprintf(msg, sizeof(msg) - 1, "Error: Can't open %d device, %s", PFDEV, strerror(errno));
536 	logmessage(1, msg, "pf", 0);
537 	return;
538      }
539 
540 
541    bzero(&table, sizeof(struct pfioc_table));
542    bzero(&pfr, sizeof(struct pfr_addr));
543    pfr.pfra_af = AF_INET;
544    pfr.pfra_net = 32;
545    table.pfrio_buffer = &pfr;
546    table.pfrio_size = 1;
547    table.pfrio_esize = sizeof(pfr);
548    strncpy(table.pfrio_table.pfrt_anchor, pfp->anchorname, PF_ANCHOR_NAME_SIZE-1);
549    switch(bd->mode & FWSAM_HOW)
550      {
551       case FWSAM_HOW_THIS:
552 	strncpy(table.pfrio_table.pfrt_name, "blockinout", PF_TABLE_NAME_SIZE - 1);
553 	break;
554       case FWSAM_HOW_IN:
555 	strncpy(table.pfrio_table.pfrt_name, "blockin", PF_TABLE_NAME_SIZE - 1);
556 	break;
557       case FWSAM_HOW_OUT:
558 	strncpy(table.pfrio_table.pfrt_name, "blockout", PF_TABLE_NAME_SIZE - 1);
559 	break;
560       case FWSAM_HOW_INOUT:
561 	strncpy(table.pfrio_table.pfrt_name, "blockinout", PF_TABLE_NAME_SIZE - 1);
562 	break;
563      }
564 
565 
566    /* BLOCK */
567    if (bd->block)
568      {
569 	snprintf(msg, sizeof(msg) - 1, "Info: Blocking ip %s", inettoa(bd->blockip));
570 	logmessage(3, msg, "pf", 0);
571 	switch(bd->mode & FWSAM_HOW)
572 	  {
573 
574 	   case FWSAM_HOW_THIS:	       /* We Need a rule for this */
575 	     /* No yet, because the need to track the rule number (rn) to delete it */
576 	     /* Handled as HOW_INOUT */
577 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
578 	     break;
579 
580 	   case FWSAM_HOW_IN:     /* ruleset : IN */
581 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
582 	     break;
583 
584 	   case FWSAM_HOW_OUT:    /* ruleset : OUT */
585 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
586 	     break;
587 
588 	   case FWSAM_HOW_INOUT:  /* ruleset : INOUT */
589 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
590 	     break;
591 
592 	  }
593 	if(ioctl(pfdev, DIOCRADDADDRS, &table) < 0)
594 	  {
595 	     snprintf(msg, sizeof(msg) - 1, "Error: Can't Block ip %s (%s)", inettoa(bd->blockip), strerror(errno));
596 	     logmessage(1, msg, "pf", 0);
597 	     return;	       /* TODO: Should I return a negativa value ?, what if It Fails ? It will try to unblock it lather ? */
598 	  }
599      }				       /* BLOCK */
600    else   /* UNBLOCK */
601      {
602 	snprintf(msg, sizeof(msg) - 1, "Info: Unblocking ip %s", inettoa(bd->blockip));
603 	logmessage(3, msg, "pf", 0);
604 
605 
606 	switch(bd->mode & FWSAM_HOW)
607 	  {
608 
609 	   case FWSAM_HOW_THIS:	       /* We Need a rule for this */
610 	     			       /* Handled as INOUT */
611 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
612 	     break;
613 
614 	   case FWSAM_HOW_IN:	       /* Uses the table */
615 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
616 	     break;
617 
618 	   case FWSAM_HOW_OUT:
619 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
620 	     break;
621 
622 	   case FWSAM_HOW_INOUT:
623 	     pfr.pfra_u._pfra_ip4addr.s_addr = (u_int32_t) bd->blockip;
624 	     break;
625 
626 	  }
627 	if(ioctl(pfdev, DIOCRDELADDRS, &table) < 0)
628 	  {
629 	     snprintf(msg, sizeof(msg) - 1, "Error: Can't Unblock ip %s (%s)", inettoa(bd->blockip), strerror(errno));
630 	     logmessage(1, msg, "pf", 0);
631 	     return;
632 	  }
633      }				       /* UNBLOCK */
634 
635    close(pfdev);
636    return;
637 }				       /* PFBLOCK */
638 
639 #endif				/* __SSP_PF_C__ */
640 
641 #endif                         /* OpenBSD || FreeBSD || NetBSD */
642 #endif /* USE_SSP_PF */
643 
644