Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

fw-pf.c

Go to the documentation of this file.
00001 /*
00002  * fw-pf.c
00003  *
00004  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: fw-pf.c,v 1.21 2005/03/15 05:05:37 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <sys/types.h>
00012 #include <sys/ioctl.h>
00013 #include <sys/socket.h>
00014 
00015 #include <net/if.h>
00016 #include <netinet/in.h>
00017 #include <net/pfvar.h>
00018 
00019 #include <assert.h>
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 
00027 #include "dnet.h"
00028 
00029 /*
00030  * XXX - cope with moving pf API
00031  */
00032 #if defined(DIOCRCLRTABLES)
00033 /* XXX - can't isolate the following change:
00034  *     $OpenBSD: pfvar.h,v 1.112 2002/12/17 12:30:13 mcbride Exp $
00035  *  so i'll take 1.119's DIOCRCLRTABLES - 12 days of pf unsupported.
00036  */
00037 # define HAVE_PF_CHANGE_GET_TICKET      1
00038 /* OpenBSD 3.3+ - 3.6 */
00039 /*     $OpenBSD: pfvar.h,v 1.197 2004/06/14 20:53:27 cedric Exp $ */
00040 /*     $OpenBSD: pfvar.h,v 1.130 2003/01/09 10:40:45 cedric Exp $ */
00041 /*     $OpenBSD: pfvar.h,v 1.127 2003/01/05 22:14:23 dhartmei Exp $ */
00042 # define PFRA_ADDR(ra)  (ra)->addr.v.a.addr.v4.s_addr
00043 # define PFRA_MASK(ra)  (ra)->addr.v.a.mask.v4.s_addr
00044 # define pfioc_changerule       pfioc_rule
00045 # define oldrule        rule
00046 # define newrule        rule
00047 #elif defined(DIOCBEGINADDRS)
00048 /*     $OpenBSD: pfvar.h,v 1.102 2002/11/23 05:16:58 mcbride Exp $ */
00049 # define PFRA_ADDR(ra)  (ra)->addr.addr.v4.s_addr
00050 # define PFRA_MASK(ra)  (ra)->addr.mask.v4.s_addr
00051 #elif defined(PFRULE_FRAGMENT)
00052 /* OpenBSD 3.2 */
00053 /*     $OpenBSD: pfvar.h,v 1.68 2002/04/24 18:10:25 dhartmei Exp $ */
00054 # define PFRA_ADDR(ra)  (ra)->addr.addr.v4.s_addr
00055 # define PFRA_MASK(ra)  (ra)->mask.v4.s_addr
00056 #elif defined (PF_AEQ)
00057 /* OpenBSD 3.1 */
00058 /*     $OpenBSD: pfvar.h,v 1.51 2001/09/15 03:54:40 frantzen Exp $ */
00059 # define PFRA_ADDR(ra)  (ra)->addr.v4.s_addr
00060 # define PFRA_MASK(ra)  (ra)->mask.v4.s_addr
00061 #else
00062 /* OpenBSD 3.0 */
00063 # define PFRA_ADDR(ra)  (ra)->addr
00064 # define PFRA_ADDR(ra)  (ra)->mask
00065 #endif
00066 
00067 struct fw_handle {
00068         int     fd;
00069 };
00070 
00071 static void
00072 fr_to_pr(const struct fw_rule *fr, struct pf_rule *pr)
00073 {
00074         memset(pr, 0, sizeof(*pr));
00075         
00076         strlcpy(pr->ifname, fr->fw_device, sizeof(pr->ifname));
00077         
00078         pr->action = (fr->fw_op == FW_OP_ALLOW) ? PF_PASS : PF_DROP;
00079         pr->direction = (fr->fw_dir == FW_DIR_IN) ? PF_IN : PF_OUT;
00080         pr->proto = fr->fw_proto;
00081 
00082         pr->af = AF_INET;
00083         PFRA_ADDR(&pr->src) = fr->fw_src.addr_ip;
00084         addr_btom(fr->fw_src.addr_bits, &(PFRA_MASK(&pr->src)), IP_ADDR_LEN);
00085         
00086         PFRA_ADDR(&pr->dst) = fr->fw_dst.addr_ip;
00087         addr_btom(fr->fw_dst.addr_bits, &(PFRA_MASK(&pr->dst)), IP_ADDR_LEN);
00088         
00089         switch (fr->fw_proto) {
00090         case IP_PROTO_ICMP:
00091                 if (fr->fw_sport[1])
00092                         pr->type = (u_char)(fr->fw_sport[0] &
00093                             fr->fw_sport[1]) + 1;
00094                 if (fr->fw_dport[1])
00095                         pr->code = (u_char)(fr->fw_dport[0] &
00096                             fr->fw_dport[1]) + 1;
00097                 break;
00098         case IP_PROTO_TCP:
00099         case IP_PROTO_UDP:
00100                 pr->src.port[0] = htons(fr->fw_sport[0]);
00101                 pr->src.port[1] = htons(fr->fw_sport[1]);
00102                 if (pr->src.port[0] == pr->src.port[1]) {
00103                         pr->src.port_op = PF_OP_EQ;
00104                 } else
00105                         pr->src.port_op = PF_OP_IRG;
00106 
00107                 pr->dst.port[0] = htons(fr->fw_dport[0]);
00108                 pr->dst.port[1] = htons(fr->fw_dport[1]);
00109                 if (pr->dst.port[0] == pr->dst.port[1]) {
00110                         pr->dst.port_op = PF_OP_EQ;
00111                 } else
00112                         pr->dst.port_op = PF_OP_IRG;
00113                 break;
00114         }
00115 }
00116 
00117 static int
00118 pr_to_fr(const struct pf_rule *pr, struct fw_rule *fr)
00119 {
00120         memset(fr, 0, sizeof(*fr));
00121         
00122         strlcpy(fr->fw_device, pr->ifname, sizeof(fr->fw_device));
00123 
00124         if (pr->action == PF_DROP)
00125                 fr->fw_op = FW_OP_BLOCK;
00126         else if (pr->action == PF_PASS)
00127                 fr->fw_op = FW_OP_ALLOW;
00128         else
00129                 return (-1);
00130         
00131         fr->fw_dir = pr->direction == PF_IN ? FW_DIR_IN : FW_DIR_OUT;
00132         fr->fw_proto = pr->proto;
00133 
00134         if (pr->af != AF_INET)
00135                 return (-1);
00136         
00137         fr->fw_src.addr_type = ADDR_TYPE_IP;
00138         addr_mtob(&(PFRA_MASK(&pr->src)), IP_ADDR_LEN, &fr->fw_src.addr_bits);
00139         fr->fw_src.addr_ip = PFRA_ADDR(&pr->src);
00140         
00141         fr->fw_dst.addr_type = ADDR_TYPE_IP;
00142         addr_mtob(&(PFRA_MASK(&pr->dst)), IP_ADDR_LEN, &fr->fw_dst.addr_bits);
00143         fr->fw_dst.addr_ip = PFRA_ADDR(&pr->dst);
00144         
00145         switch (fr->fw_proto) {
00146         case IP_PROTO_ICMP:
00147                 if (pr->type) {
00148                         fr->fw_sport[0] = pr->type - 1;
00149                         fr->fw_sport[1] = 0xff;
00150                 }
00151                 if (pr->code) {
00152                         fr->fw_dport[0] = pr->code - 1;
00153                         fr->fw_dport[1] = 0xff;
00154                 }
00155                 break;
00156         case IP_PROTO_TCP:
00157         case IP_PROTO_UDP:
00158                 fr->fw_sport[0] = ntohs(pr->src.port[0]);
00159                 fr->fw_sport[1] = ntohs(pr->src.port[1]);
00160                 if (pr->src.port_op == PF_OP_EQ)
00161                         fr->fw_sport[1] = fr->fw_sport[0];
00162 
00163                 fr->fw_dport[0] = ntohs(pr->dst.port[0]);
00164                 fr->fw_dport[1] = ntohs(pr->dst.port[1]);
00165                 if (pr->dst.port_op == PF_OP_EQ)
00166                         fr->fw_dport[1] = fr->fw_dport[0];
00167         }
00168         return (0);
00169 }
00170 
00171 #ifdef HAVE_PF_CHANGE_GET_TICKET
00172 static int
00173 _fw_cmp(const struct fw_rule *a, const struct fw_rule *b)
00174 {
00175         if (strcmp(a->fw_device, b->fw_device) != 0 || a->fw_op != b->fw_op ||
00176                         a->fw_dir != b->fw_dir || a->fw_proto != b->fw_proto ||
00177             addr_cmp(&a->fw_src, &b->fw_src) != 0 ||
00178             addr_cmp(&a->fw_dst, &b->fw_dst) != 0 ||
00179             memcmp(a->fw_sport, b->fw_sport, sizeof(a->fw_sport)) != 0 ||
00180             memcmp(a->fw_dport, b->fw_dport, sizeof(a->fw_dport)) != 0)
00181                 return (-1);
00182         return (0);
00183 }
00184 #endif
00185 
00186 fw_t *
00187 fw_open(void)
00188 {
00189         fw_t *fw;
00190 
00191         if ((fw = calloc(1, sizeof(*fw))) != NULL) {
00192                 if ((fw->fd = open("/dev/pf", O_RDWR)) < 0)
00193                         return (fw_close(fw));
00194         }
00195         return (fw);
00196 }
00197 
00198 int
00199 fw_add(fw_t *fw, const struct fw_rule *rule)
00200 {
00201         struct pfioc_changerule pcr;
00202 
00203         assert(fw != NULL && rule != NULL);
00204         memset(&pcr, 0, sizeof(pcr));
00205 #ifdef HAVE_PF_CHANGE_GET_TICKET
00206         {
00207                 struct fw_rule fr;
00208                 
00209                 if (ioctl(fw->fd, DIOCGETRULES, &pcr) < 0)
00210                         return (-1);
00211                 while ((int)--pcr.nr >= 0) {
00212                         if (ioctl(fw->fd, DIOCGETRULE, &pcr) == 0 &&
00213                             pr_to_fr(&pcr.rule, &fr) == 0) {
00214                                 if (_fw_cmp(rule, &fr) == 0) {
00215                                         errno = EEXIST;
00216                                         return (-1);
00217                                 }
00218                         }
00219                 }
00220         }
00221 #endif
00222 #ifdef DIOCBEGINADDRS
00223         {
00224                 struct pfioc_pooladdr ppa;
00225                 
00226                 if (ioctl(fw->fd, DIOCBEGINADDRS, &ppa) < 0)
00227                         return (-1);
00228                 pcr.pool_ticket = ppa.ticket;
00229         }
00230 #endif
00231         pcr.action = PF_CHANGE_ADD_TAIL;
00232         fr_to_pr(rule, &pcr.newrule);
00233         
00234         return (ioctl(fw->fd, DIOCCHANGERULE, &pcr));
00235 }
00236 
00237 int
00238 fw_delete(fw_t *fw, const struct fw_rule *rule)
00239 {
00240         struct pfioc_changerule pcr;
00241         
00242         assert(fw != NULL && rule != NULL);
00243         memset(&pcr, 0, sizeof(pcr));
00244 #ifdef HAVE_PF_CHANGE_GET_TICKET
00245         {
00246                 struct fw_rule fr;
00247                 int found = 0;
00248                 
00249                 if (ioctl(fw->fd, DIOCGETRULES, &pcr) < 0)
00250                         return (-1);
00251                 while ((int)--pcr.nr >= 0) {
00252                         if (ioctl(fw->fd, DIOCGETRULE, &pcr) == 0 &&
00253                             pr_to_fr(&pcr.rule, &fr) == 0) {
00254                                 if (_fw_cmp(rule, &fr) == 0) {
00255                                         found = 1;
00256                                         break;
00257                                 }
00258                         }
00259                 }
00260                 if (!found) {
00261                         errno = ENOENT;
00262                         return (-1);
00263                 }
00264         }
00265 #endif
00266 #ifdef DIOCBEGINADDRS
00267         {
00268                 struct pfioc_pooladdr ppa;
00269                 
00270                 if (ioctl(fw->fd, DIOCBEGINADDRS, &ppa) < 0)
00271                         return (-1);
00272                 pcr.pool_ticket = ppa.ticket;
00273         }
00274 #endif
00275         pcr.action = PF_CHANGE_REMOVE;
00276         fr_to_pr(rule, &pcr.oldrule);
00277         
00278         return (ioctl(fw->fd, DIOCCHANGERULE, &pcr));
00279 }
00280 
00281 int
00282 fw_loop(fw_t *fw, fw_handler callback, void *arg)
00283 {
00284         struct pfioc_rule pr;
00285         struct fw_rule fr;
00286         uint32_t n, max;
00287         int ret = 0;
00288 
00289         memset(&pr, 0, sizeof(pr));
00290         if (ioctl(fw->fd, DIOCGETRULES, &pr) < 0)
00291                 return (-1);
00292         
00293         for (n = 0, max = pr.nr; n < max; n++) {
00294                 pr.nr = n;
00295                 
00296                 if ((ret = ioctl(fw->fd, DIOCGETRULE, &pr)) < 0)
00297                         break;
00298 #ifdef PF_TABLE_NAME_SIZE
00299                 /* XXX - actually in r1.125, not 1.126 */
00300                 if (pr.rule.src.addr.type == PF_ADDR_TABLE ||
00301                     pr.rule.dst.addr.type == PF_ADDR_TABLE)
00302                         continue;
00303 #endif
00304                 if (pr_to_fr(&pr.rule, &fr) < 0)
00305                         continue;
00306                 if ((ret = callback(&fr, arg)) != 0)
00307                         break;
00308         }
00309         return (ret);
00310 }
00311 
00312 fw_t *
00313 fw_close(fw_t *fw)
00314 {
00315         if (fw != NULL) {
00316                 if (fw->fd >= 0)
00317                         close(fw->fd);
00318                 free(fw);
00319         }
00320         return (NULL);
00321 }

Generated on Sun May 14 14:51:11 2006 by  doxygen 1.4.2