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