00001
00002
00003
00004
00005
00006
00007
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_
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)
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 }