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

fw-ipfw.c

Go to the documentation of this file.
00001 /*
00002  * fw-ipfw.c
00003  *
00004  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: fw-ipfw.c,v 1.16 2004/01/14 04:52:10 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <sys/types.h>
00012 #include <sys/queue.h>
00013 #include <sys/socket.h>
00014 
00015 #include <net/if.h>
00016 #include <netinet/in.h>
00017 #include <netinet/ip_fw.h>
00018 
00019 #include <assert.h>
00020 #include <errno.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 
00026 #include "dnet.h"
00027 
00028 struct fw_handle {
00029         int     fd;
00030 };
00031 
00032 static void
00033 fr_to_ipfw_device(const char *device, char *name, short *unit)
00034 {
00035         char *p;
00036 
00037         p = strpbrk(device, "0123456789");
00038         *unit = atoi(p);
00039         strlcpy(name, device, p - device + 1);
00040 }
00041 
00042 static void
00043 fr_to_ipfw(const struct fw_rule *fr, struct ip_fw *ipfw)
00044 {
00045         int i;
00046         
00047         memset(ipfw, 0, sizeof(*ipfw));
00048 
00049         if (fr->fw_dir == FW_DIR_IN) {
00050                 if (*fr->fw_device != '\0') {
00051                         fr_to_ipfw_device(fr->fw_device,
00052                             ipfw->fw_in_if.fu_via_if.name,
00053                             &ipfw->fw_in_if.fu_via_if.unit);
00054                         ipfw->fw_flg |= IP_FW_F_IIFNAME;
00055                 }
00056                 ipfw->fw_flg |= IP_FW_F_IN;
00057         } else {
00058                 if (*fr->fw_device != '\0') {
00059                         fr_to_ipfw_device(fr->fw_device,
00060                             ipfw->fw_out_if.fu_via_if.name,
00061                             &ipfw->fw_out_if.fu_via_if.unit);
00062                         ipfw->fw_flg |= IP_FW_F_OIFNAME;
00063                 }
00064                 ipfw->fw_flg |= IP_FW_F_OUT;
00065         }
00066         if (fr->fw_op == FW_OP_ALLOW)
00067                 ipfw->fw_flg |= IP_FW_F_ACCEPT;
00068         else
00069                 ipfw->fw_flg |= IP_FW_F_DENY;
00070         
00071         ipfw->fw_prot = fr->fw_proto;
00072         ipfw->fw_src.s_addr = fr->fw_src.addr_ip;
00073         ipfw->fw_dst.s_addr = fr->fw_dst.addr_ip;
00074         addr_btom(fr->fw_src.addr_bits, &ipfw->fw_smsk.s_addr, IP_ADDR_LEN);
00075         addr_btom(fr->fw_dst.addr_bits, &ipfw->fw_dmsk.s_addr, IP_ADDR_LEN);
00076 
00077         switch (fr->fw_proto) {
00078         case IP_PROTO_TCP:
00079         case IP_PROTO_UDP:
00080                 i = 0;
00081                 if (fr->fw_sport[0] != fr->fw_sport[1]) {
00082                         ipfw->fw_flg |= IP_FW_F_SRNG;
00083                         ipfw->fw_uar.fw_pts[i++] = fr->fw_sport[0];
00084                         ipfw->fw_uar.fw_pts[i++] = fr->fw_sport[1];
00085                         IP_FW_SETNSRCP(ipfw, 2);
00086                 } else if (fr->fw_sport[0] > 0) {
00087                         ipfw->fw_uar.fw_pts[i++] = fr->fw_sport[0];
00088                         IP_FW_SETNSRCP(ipfw, 1);
00089                 }
00090                 if (fr->fw_dport[0] != fr->fw_dport[1]) {
00091                         ipfw->fw_flg |= IP_FW_F_DRNG;
00092                         ipfw->fw_uar.fw_pts[i++] = fr->fw_dport[0];
00093                         ipfw->fw_uar.fw_pts[i++] = fr->fw_dport[1];
00094                         IP_FW_SETNDSTP(ipfw, 2);
00095                 } else if (fr->fw_dport[0] > 0) {
00096                         ipfw->fw_uar.fw_pts[i++] = fr->fw_dport[0];
00097                         IP_FW_SETNDSTP(ipfw, 1);
00098                 }
00099                 break;
00100         case IP_PROTO_ICMP:
00101                 if (fr->fw_sport[1]) {
00102                         ipfw->fw_uar.fw_icmptypes[fr->fw_sport[0] / 32] |=
00103                             1 << (fr->fw_sport[0] % 32);
00104                         ipfw->fw_flg |= IP_FW_F_ICMPBIT;
00105                 }
00106                 /* XXX - no support for ICMP code. */
00107                 break;
00108         }
00109 }
00110 
00111 static void
00112 ipfw_to_fr(const struct ip_fw *ipfw, struct fw_rule *fr)
00113 {
00114         int i;
00115         
00116         memset(fr, 0, sizeof(*fr));
00117 
00118         if ((ipfw->fw_flg & IP_FW_F_IN) && *ipfw->fw_in_if.fu_via_if.name)
00119                 snprintf(fr->fw_device, sizeof(fr->fw_device), "%s%d",
00120                     ipfw->fw_in_if.fu_via_if.name,
00121                     ipfw->fw_in_if.fu_via_if.unit);
00122         else if ((ipfw->fw_flg & IP_FW_F_OUT) &&
00123             *ipfw->fw_out_if.fu_via_if.name)
00124                 snprintf(fr->fw_device, sizeof(fr->fw_device), "%s%d",
00125                     ipfw->fw_out_if.fu_via_if.name,
00126                     ipfw->fw_out_if.fu_via_if.unit);
00127         
00128         fr->fw_op = (ipfw->fw_flg & IP_FW_F_ACCEPT) ?
00129             FW_OP_ALLOW : FW_OP_BLOCK;
00130         fr->fw_dir = (ipfw->fw_flg & IP_FW_F_IN) ? FW_DIR_IN : FW_DIR_OUT;
00131         fr->fw_proto = ipfw->fw_prot;
00132 
00133         fr->fw_src.addr_type = fr->fw_dst.addr_type = ADDR_TYPE_IP;
00134         fr->fw_src.addr_ip = ipfw->fw_src.s_addr;
00135         fr->fw_dst.addr_ip = ipfw->fw_dst.s_addr;
00136         addr_mtob(&ipfw->fw_smsk.s_addr, IP_ADDR_LEN, &fr->fw_src.addr_bits);
00137         addr_mtob(&ipfw->fw_dmsk.s_addr, IP_ADDR_LEN, &fr->fw_dst.addr_bits);
00138 
00139         switch (fr->fw_proto) {
00140         case IP_PROTO_TCP:
00141         case IP_PROTO_UDP:
00142                 if ((ipfw->fw_flg & IP_FW_F_SRNG) &&
00143                     IP_FW_GETNSRCP(ipfw) == 2) {
00144                         fr->fw_sport[0] = ipfw->fw_uar.fw_pts[0];
00145                         fr->fw_sport[1] = ipfw->fw_uar.fw_pts[1];
00146                 } else if (IP_FW_GETNSRCP(ipfw) == 1) {
00147                         fr->fw_sport[0] = fr->fw_sport[1] =
00148                             ipfw->fw_uar.fw_pts[0];
00149                 } else if (IP_FW_GETNSRCP(ipfw) == 0) {
00150                         fr->fw_sport[0] = 0;
00151                         fr->fw_sport[1] = TCP_PORT_MAX;
00152                 }
00153                 
00154                 if ((ipfw->fw_flg & IP_FW_F_DRNG) &&
00155                     IP_FW_GETNDSTP(ipfw) == 2) {
00156                         i = IP_FW_GETNSRCP(ipfw);
00157                         fr->fw_dport[0] = ipfw->fw_uar.fw_pts[i];
00158                         fr->fw_dport[1] = ipfw->fw_uar.fw_pts[i + 1];
00159                 } else if (IP_FW_GETNDSTP(ipfw) == 1) {
00160                         i = IP_FW_GETNSRCP(ipfw);
00161                         fr->fw_dport[0] = fr->fw_dport[1] =
00162                             ipfw->fw_uar.fw_pts[i];
00163                 } else if (IP_FW_GETNDSTP(ipfw) == 0) {
00164                         fr->fw_dport[0] = 0;
00165                         fr->fw_dport[1] = TCP_PORT_MAX;
00166                 }
00167                 break;
00168         case IP_PROTO_ICMP:
00169                 if (ipfw->fw_flg & IP_FW_F_ICMPBIT) {
00170                         for (i = 0; i < IP_FW_ICMPTYPES_DIM * 32; i++) {
00171                                 if (ipfw->fw_uar.fw_icmptypes[i / 32] &
00172                                     (1U << (i % 32))) {
00173                                         fr->fw_sport[0] = i;
00174                                         fr->fw_sport[1] = 0xff;
00175                                         break;
00176                                 }
00177                         }
00178                 }
00179                 /* XXX - no support for ICMP code. */
00180                 break;
00181         }
00182 }
00183 
00184 fw_t *
00185 fw_open(void)
00186 {
00187         fw_t *fw;
00188         
00189         if ((fw = calloc(1, sizeof(*fw))) != NULL) {
00190                 if ((fw->fd = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) < 0)
00191                         return (fw_close(fw));
00192         }
00193         return (fw);
00194 }
00195 
00196 int
00197 fw_add(fw_t *fw, const struct fw_rule *rule)
00198 {
00199         struct ip_fw ipfw;
00200         
00201         assert(fw != NULL && rule != NULL);
00202 
00203         fr_to_ipfw(rule, &ipfw);
00204 
00205         return (setsockopt(fw->fd, IPPROTO_IP, IP_FW_ADD,
00206             &ipfw, sizeof(ipfw)));
00207 }
00208 
00209 static int
00210 fw_cmp(const struct fw_rule *a, const struct fw_rule *b)
00211 {
00212         if (strcmp(a->fw_device, b->fw_device) != 0 || a->fw_op != b->fw_op ||
00213             a->fw_dir != b->fw_dir || a->fw_proto != b->fw_proto || 
00214             addr_cmp(&a->fw_src, &b->fw_src) != 0 ||
00215             addr_cmp(&a->fw_dst, &b->fw_dst) != 0 ||
00216             memcmp(a->fw_sport, b->fw_sport, sizeof(a->fw_sport)) != 0 ||
00217             memcmp(a->fw_dport, b->fw_dport, sizeof(a->fw_dport)) != 0)
00218                 return (-1);
00219         return (0);
00220 }
00221 
00222 int
00223 fw_delete(fw_t *fw, const struct fw_rule *rule)
00224 {
00225         struct ip_fw *ipfw;
00226         struct fw_rule fr;
00227         int nbytes, nalloc, ret;
00228         u_char *buf, *new;
00229 
00230         assert(rule != NULL);
00231 
00232         nbytes = nalloc = sizeof(*ipfw);
00233         if ((buf = malloc(nbytes)) == NULL)
00234                 return (-1);
00235         
00236         while (nbytes >= nalloc) {
00237                 nalloc = nalloc * 2 + 200;
00238                 nbytes = nalloc;
00239                 if ((new = realloc(buf, nbytes)) == NULL) {
00240                         if (buf)
00241                                 free(buf);
00242                         return (-1);
00243                 }
00244                 buf = new;
00245                 if (getsockopt(fw->fd, IPPROTO_IP, IP_FW_GET,
00246                                buf, &nbytes) < 0) {
00247                         free(buf);
00248                         return (-1);
00249                 }
00250         }
00251         ret = -1;
00252 
00253         /* XXX - 65535 is the fixed ipfw default rule. */
00254         for (ipfw = (struct ip_fw *)buf; ipfw->fw_number < 65535; ipfw++) {
00255                 ipfw_to_fr(ipfw, &fr);
00256                 if (fw_cmp(&fr, rule) == 0) {
00257                         if (setsockopt(fw->fd, IPPROTO_IP, IP_FW_DEL,
00258                             ipfw, sizeof(*ipfw)) < 0)
00259                                 ret = -2;
00260                         else
00261                                 ret = 0;
00262                         break;
00263                 }
00264         }
00265         free(buf);
00266         
00267         if (ret < 0) {
00268                 if (ret == -1)
00269                         errno = ESRCH;
00270                 return (-1);
00271         }
00272         return (0);
00273 }
00274 
00275 int
00276 fw_loop(fw_t *fw, fw_handler callback, void *arg)
00277 {
00278         struct ip_fw *ipfw;
00279         struct fw_rule fr;
00280         int i, cnt, nbytes, nalloc, ret;
00281         u_char *buf, *new;
00282 
00283         nbytes = nalloc = sizeof(*ipfw);
00284         if ((buf = malloc(nbytes)) == NULL)
00285                 return (-1);
00286         
00287         while (nbytes >= nalloc) {
00288                 nalloc = nalloc * 2 + 200;
00289                 nbytes = nalloc;
00290                 if ((new = realloc(buf, nbytes)) == NULL) {
00291                         if (buf)
00292                                 free(buf);
00293                         return (-1);
00294                 }
00295                 buf = new;
00296                 if (getsockopt(fw->fd, IPPROTO_IP, IP_FW_GET,
00297                                buf, &nbytes) < 0) {
00298                         free(buf);
00299                         return (-1);
00300                 }
00301         }
00302         cnt = nbytes / sizeof(*ipfw);
00303         ipfw = (struct ip_fw *)buf;
00304         ret = 0;
00305         
00306         for (i = 0; i < cnt; i++) {
00307                 ipfw_to_fr(&ipfw[i], &fr);
00308                 if ((ret = callback(&fr, arg)) != 0)
00309                         break;
00310         }
00311         free(buf);
00312         return (ret);
00313 }
00314 
00315 fw_t *
00316 fw_close(fw_t *fw)
00317 {
00318         if (fw != NULL) {
00319                 if (fw->fd >= 0)
00320                         close(fw->fd);
00321                 free(fw);
00322         }
00323         return (NULL);
00324 }

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