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

fw-ipf.c

Go to the documentation of this file.
00001 
00002 /*
00003  * fw-ipf.c
00004  *
00005  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00006  *
00007  * $Id: fw-ipf.c,v 1.18 2005/02/16 21:42:53 dugsong Exp $
00008  */
00009 
00010 #include "config.h"
00011 
00012 #include <sys/param.h>
00013 #include <sys/types.h>
00014 #include <sys/ioctl.h>
00015 #include <sys/socket.h>
00016 
00017 #include <net/if.h>
00018 #define _NETINET_IP6_H_         /* XXX */
00019 #include <netinet/in.h>
00020 #define ip_t    ipf_ip_t
00021 #ifdef HAVE_NETINET_IP_FIL_COMPAT_H
00022 # include <netinet/ip_fil_compat.h>
00023 #else
00024 # include <netinet/ip_compat.h>
00025 #endif
00026 #include <netinet/ip_fil.h>
00027 #undef ip_t
00028 
00029 #include <assert.h>
00030 #include <errno.h>
00031 #include <fcntl.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <unistd.h>
00036 
00037 #define KMEM_NAME       "/dev/kmem"
00038 
00039 #include "dnet.h"
00040 
00041 #if !defined(fi_saddr) && !defined(fi_daddr)
00042 # define fi_saddr       fi_src.s_addr
00043 # define fi_daddr       fi_dst.s_addr
00044 #endif
00045 
00046 struct fw_handle {
00047         int     fd;
00048         int     kfd;
00049 };
00050 
00051 static void
00052 rule_to_ipf(const struct fw_rule *rule, struct frentry *fr)
00053 {
00054         memset(fr, 0, sizeof(*fr));
00055 
00056         if (*rule->fw_device != '\0') {
00057                 strlcpy(fr->fr_ifname, rule->fw_device, IFNAMSIZ);
00058                 strlcpy(fr->fr_oifname, rule->fw_device, IFNAMSIZ);
00059         }
00060         if (rule->fw_op == FW_OP_ALLOW)
00061                 fr->fr_flags |= FR_PASS;
00062         else
00063                 fr->fr_flags |= FR_BLOCK;
00064 
00065         if (rule->fw_dir == FW_DIR_IN)
00066                 fr->fr_flags |= FR_INQUE;
00067         else
00068                 fr->fr_flags |= FR_OUTQUE;
00069         
00070         fr->fr_ip.fi_p = rule->fw_proto;
00071         fr->fr_ip.fi_saddr = rule->fw_src.addr_ip;
00072         fr->fr_ip.fi_daddr = rule->fw_dst.addr_ip;
00073         addr_btom(rule->fw_src.addr_bits, &fr->fr_mip.fi_saddr, IP_ADDR_LEN);
00074         addr_btom(rule->fw_dst.addr_bits, &fr->fr_mip.fi_daddr, IP_ADDR_LEN);
00075         
00076         switch (rule->fw_proto) {
00077         case IPPROTO_ICMP:
00078                 fr->fr_icmpm = rule->fw_sport[1] << 8 |
00079                     (rule->fw_dport[1] & 0xff);
00080                 fr->fr_icmp = rule->fw_sport[0] << 8 |
00081                     (rule->fw_dport[0] & 0xff);
00082                 break;
00083         case IPPROTO_TCP:
00084         case IPPROTO_UDP:
00085                 fr->fr_sport = rule->fw_sport[0];
00086                 if (rule->fw_sport[0] != rule->fw_sport[1]) {
00087                         fr->fr_scmp = FR_INRANGE;
00088                         fr->fr_stop = rule->fw_sport[1];
00089                 } else
00090                         fr->fr_scmp = FR_EQUAL;
00091 
00092                 fr->fr_dport = rule->fw_dport[0];
00093                 if (rule->fw_dport[0] != rule->fw_dport[1]) {
00094                         fr->fr_dcmp = FR_INRANGE;
00095                         fr->fr_dtop = rule->fw_dport[1];
00096                 } else
00097                         fr->fr_dcmp = FR_EQUAL;
00098                 break;
00099         }
00100 }
00101 
00102 static void
00103 ipf_ports_to_rule(uint8_t cmp, uint16_t port, uint16_t top, uint16_t *range)
00104 {
00105         switch (cmp) {
00106         case FR_EQUAL:
00107                 range[0] = range[1] = port;
00108                 break;
00109         case FR_NEQUAL:
00110                 range[0] = port - 1;
00111                 range[1] = port + 1;
00112                 break;
00113         case FR_LESST:
00114                 range[0] = 0;
00115                 range[1] = port - 1;
00116                 break;
00117         case FR_GREATERT:
00118                 range[0] = port + 1;
00119                 range[1] = TCP_PORT_MAX;
00120                 break;
00121         case FR_LESSTE:
00122                 range[0] = 0;
00123                 range[1] = port;
00124                 break;
00125         case FR_GREATERTE:
00126                 range[0] = port;
00127                 range[1] = TCP_PORT_MAX;
00128                 break;
00129         case FR_OUTRANGE:
00130                 range[0] = port;
00131                 range[1] = top;
00132                 break;
00133         case FR_INRANGE:
00134                 range[0] = port;
00135                 range[1] = top;
00136                 break;
00137         default:
00138                 range[0] = 0;
00139                 range[1] = TCP_PORT_MAX;
00140         }
00141 }
00142 
00143 static void
00144 ipf_to_rule(const struct frentry *fr, struct fw_rule *rule)
00145 {
00146         memset(rule, 0, sizeof(*rule));
00147 
00148         strlcpy(rule->fw_device, fr->fr_ifname, sizeof(rule->fw_device));
00149         rule->fw_op = (fr->fr_flags & FR_PASS) ? FW_OP_ALLOW : FW_OP_BLOCK;
00150         rule->fw_dir = (fr->fr_flags & FR_INQUE) ? FW_DIR_IN : FW_DIR_OUT;
00151         rule->fw_proto = fr->fr_ip.fi_p;
00152 
00153         rule->fw_src.addr_type = rule->fw_dst.addr_type = ADDR_TYPE_IP;
00154         rule->fw_src.addr_ip = fr->fr_ip.fi_saddr;
00155         rule->fw_dst.addr_ip = fr->fr_ip.fi_daddr;
00156         addr_mtob(&fr->fr_mip.fi_saddr, IP_ADDR_LEN,
00157             &rule->fw_src.addr_bits);
00158         addr_mtob(&fr->fr_mip.fi_daddr, IP_ADDR_LEN,
00159             &rule->fw_dst.addr_bits);
00160         
00161         switch (rule->fw_proto) {
00162         case IPPROTO_ICMP:
00163                 rule->fw_sport[0] = ntohs(fr->fr_icmp & fr->fr_icmpm) >> 8;
00164                 rule->fw_sport[1] = ntohs(fr->fr_icmpm) >> 8;
00165                 rule->fw_dport[0] = ntohs(fr->fr_icmp & fr->fr_icmpm) & 0xff;
00166                 rule->fw_dport[1] = ntohs(fr->fr_icmpm) & 0xff;
00167                 break;
00168         case IPPROTO_TCP:
00169         case IPPROTO_UDP:
00170                 ipf_ports_to_rule(fr->fr_scmp, fr->fr_sport,
00171                     fr->fr_stop, rule->fw_sport);
00172                 ipf_ports_to_rule(fr->fr_dcmp, fr->fr_dport,
00173                     fr->fr_dtop, rule->fw_dport);
00174                 break;
00175         }
00176 }
00177 
00178 fw_t *
00179 fw_open(void)
00180 {
00181         fw_t *fw;
00182         
00183         if ((fw = calloc(1, sizeof(*fw))) != NULL) {
00184                 fw->fd = fw->kfd = -1;
00185                 if ((fw->fd = open(IPL_NAME, O_RDWR, 0)) < 0)
00186                         return (fw_close(fw));
00187                 if ((fw->kfd = open(KMEM_NAME, O_RDONLY)) < 0)
00188                         return (fw_close(fw));
00189         }
00190         return (fw);
00191 }
00192 
00193 int
00194 fw_add(fw_t *fw, const struct fw_rule *rule)
00195 {
00196         struct frentry fr;
00197         
00198         assert(fw != NULL && rule != NULL);
00199         
00200         rule_to_ipf(rule, &fr);
00201         
00202         return (ioctl(fw->fd, SIOCADDFR, &fr));
00203 }
00204 
00205 int
00206 fw_delete(fw_t *fw, const struct fw_rule *rule)
00207 {
00208         struct frentry fr;
00209         
00210         assert(fw != NULL && rule != NULL);
00211 
00212         rule_to_ipf(rule, &fr);
00213         
00214         return (ioctl(fw->fd, SIOCDELFR, &fr));
00215 }
00216 
00217 static int
00218 fw_kcopy(fw_t *fw, u_char *buf, off_t pos, size_t n)
00219 {
00220         int i;
00221         
00222         if (lseek(fw->kfd, pos, 0) < 0)
00223                 return (-1);
00224 
00225         while ((i = read(fw->kfd, buf, n)) < n) {
00226                 if (i <= 0)
00227                         return (-1);
00228                 buf += i;
00229                 n -= i;
00230         }
00231         return (0);
00232 }
00233 
00234 int
00235 fw_loop(fw_t *fw, fw_handler callback, void *arg)
00236 {
00237         struct friostat fio;
00238         struct friostat *fiop = &fio;
00239         struct frentry *frp, fr;
00240         struct fw_rule rule;
00241         int ret;
00242         
00243         memset(&fio, 0, sizeof(fio));
00244 #ifdef __OpenBSD__
00245         if (ioctl(fw->fd, SIOCGETFS, fiop) < 0)
00246 #else
00247         if (ioctl(fw->fd, SIOCGETFS, &fiop) < 0)        /* XXX - darren! */
00248 #endif
00249                 return (-1);
00250 
00251         for (frp = fio.f_fout[(int)fio.f_active]; frp != NULL;
00252             frp = fr.fr_next) {
00253                 if (fw_kcopy(fw, (u_char *)&fr, (u_long)frp, sizeof(fr)) < 0)
00254                         return (-1);
00255                 ipf_to_rule(&fr, &rule);
00256                 if ((ret = callback(&rule, arg)) != 0)
00257                         return (ret);
00258         }
00259         for (frp = fio.f_fin[(int)fio.f_active]; frp != NULL;
00260             frp = fr.fr_next) {
00261                 if (fw_kcopy(fw, (u_char *)&fr, (u_long)frp, sizeof(fr)) < 0)
00262                         return (-1);
00263                 ipf_to_rule(&fr, &rule);
00264                 if ((ret = callback(&rule, arg)) != 0)
00265                         return (ret);
00266         }
00267         return (0);
00268 }
00269 
00270 fw_t *
00271 fw_close(fw_t *fw)
00272 {
00273         if (fw != NULL) {
00274                 if (fw->fd >= 0)
00275                         close(fw->fd);
00276                 if (fw->kfd >= 0)
00277                         close(fw->kfd);
00278                 free(fw);
00279         }
00280         return (NULL);
00281 }

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