00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "config.h"
00010
00011 #include <sys/types.h>
00012 #include <sys/socket.h>
00013
00014 #include <netinet/in.h>
00015 #include <netinet/ip.h>
00016 #include <netinet/tcp.h>
00017 #include <netinet/udp.h>
00018 #undef __USE_BSD
00019 #include <netinet/ip_icmp.h>
00020 #include <linux/if.h>
00021 #ifdef HAVE_LINUX_IP_FW_H
00022 #include <linux/ip_fw.h>
00023 #elif defined(HAVE_LINUX_IP_FWCHAINS_H)
00024 #include <linux/ip_fwchains.h>
00025 #elif defined(HAVE_LINUX_NETFILTER_IPV4_IPCHAINS_CORE_H)
00026 #include <linux/netfilter_ipv4/ipchains_core.h>
00027 #endif
00028
00029 #include <assert.h>
00030 #include <errno.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <unistd.h>
00035
00036 #include "dnet.h"
00037
00038 #define PROC_IPCHAINS_FILE "/proc/net/ip_fwchains"
00039
00040 struct fw_handle {
00041 int fd;
00042 };
00043
00044 static void
00045 fr_to_fwc(const struct fw_rule *fr, struct ip_fwchange *fwc)
00046 {
00047 memset(fwc, 0, sizeof(*fwc));
00048
00049 strlcpy(fwc->fwc_rule.ipfw.fw_vianame, fr->fw_device, IFNAMSIZ);
00050
00051 if (fr->fw_op == FW_OP_ALLOW)
00052 strlcpy(fwc->fwc_rule.label, IP_FW_LABEL_ACCEPT,
00053 sizeof(fwc->fwc_rule.label));
00054 else
00055 strlcpy(fwc->fwc_rule.label, IP_FW_LABEL_BLOCK,
00056 sizeof(fwc->fwc_rule.label));
00057
00058 if (fr->fw_dir == FW_DIR_IN)
00059 strlcpy(fwc->fwc_label, IP_FW_LABEL_INPUT,
00060 sizeof(fwc->fwc_label));
00061 else
00062 strlcpy(fwc->fwc_label, IP_FW_LABEL_OUTPUT,
00063 sizeof(fwc->fwc_label));
00064
00065 fwc->fwc_rule.ipfw.fw_proto = fr->fw_proto;
00066 fwc->fwc_rule.ipfw.fw_src.s_addr = fr->fw_src.addr_ip;
00067 fwc->fwc_rule.ipfw.fw_dst.s_addr = fr->fw_dst.addr_ip;
00068 addr_btom(fr->fw_src.addr_bits, &fwc->fwc_rule.ipfw.fw_smsk.s_addr,
00069 IP_ADDR_LEN);
00070 addr_btom(fr->fw_dst.addr_bits, &fwc->fwc_rule.ipfw.fw_dmsk.s_addr,
00071 IP_ADDR_LEN);
00072
00073
00074 fwc->fwc_rule.ipfw.fw_spts[0] = fr->fw_sport[0];
00075 fwc->fwc_rule.ipfw.fw_spts[1] = fr->fw_sport[1];
00076 fwc->fwc_rule.ipfw.fw_dpts[0] = fr->fw_dport[0];
00077 fwc->fwc_rule.ipfw.fw_dpts[1] = fr->fw_dport[1];
00078 }
00079
00080 static void
00081 fwc_to_fr(const struct ip_fwchange *fwc, struct fw_rule *fr)
00082 {
00083 memset(fr, 0, sizeof(*fr));
00084
00085 strlcpy(fr->fw_device, fwc->fwc_rule.ipfw.fw_vianame,
00086 sizeof(fr->fw_device));
00087
00088 if (strcmp(fwc->fwc_rule.label, IP_FW_LABEL_ACCEPT) == 0)
00089 fr->fw_op = FW_OP_ALLOW;
00090 else
00091 fr->fw_op = FW_OP_BLOCK;
00092
00093 if (strcmp(fwc->fwc_label, IP_FW_LABEL_INPUT) == 0)
00094 fr->fw_dir = FW_DIR_IN;
00095 else
00096 fr->fw_dir = FW_DIR_OUT;
00097
00098 fr->fw_proto = fwc->fwc_rule.ipfw.fw_proto;
00099 fr->fw_src.addr_type = fr->fw_dst.addr_type = ADDR_TYPE_IP;
00100 fr->fw_src.addr_ip = fwc->fwc_rule.ipfw.fw_src.s_addr;
00101 fr->fw_dst.addr_ip = fwc->fwc_rule.ipfw.fw_dst.s_addr;
00102 addr_mtob(&fwc->fwc_rule.ipfw.fw_smsk.s_addr, IP_ADDR_LEN,
00103 &fr->fw_src.addr_bits);
00104 addr_mtob(&fwc->fwc_rule.ipfw.fw_dmsk.s_addr, IP_ADDR_LEN,
00105 &fr->fw_dst.addr_bits);
00106
00107
00108 fr->fw_sport[0] = fwc->fwc_rule.ipfw.fw_spts[0];
00109 fr->fw_sport[1] = fwc->fwc_rule.ipfw.fw_spts[1];
00110 fr->fw_dport[0] = fwc->fwc_rule.ipfw.fw_dpts[0];
00111 fr->fw_dport[1] = fwc->fwc_rule.ipfw.fw_dpts[1];
00112 }
00113
00114 fw_t *
00115 fw_open(void)
00116 {
00117 fw_t *fw;
00118
00119 if ((fw = calloc(1, sizeof(*fw))) != NULL) {
00120 if ((fw->fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
00121 return (fw_close(fw));
00122 }
00123 return (fw);
00124 }
00125
00126 int
00127 fw_add(fw_t *fw, const struct fw_rule *rule)
00128 {
00129 struct ip_fwchange fwc;
00130
00131 fr_to_fwc(rule, &fwc);
00132
00133 return (setsockopt(fw->fd, IPPROTO_IP, IP_FW_APPEND,
00134 &fwc, sizeof(fwc)));
00135 }
00136
00137 int
00138 fw_delete(fw_t *fw, const struct fw_rule *rule)
00139 {
00140 struct ip_fwchange fwc;
00141
00142 fr_to_fwc(rule, &fwc);
00143
00144 return (setsockopt(fw->fd, IPPROTO_IP, IP_FW_DELETE,
00145 &fwc, sizeof(fwc)));
00146 }
00147
00148 int
00149 fw_loop(fw_t *fw, fw_handler callback, void *arg)
00150 {
00151 FILE *fp;
00152 struct ip_fwchange fwc;
00153 struct fw_rule fr;
00154 char buf[BUFSIZ];
00155 u_int phi, plo, bhi, blo, tand, txor;
00156 int ret;
00157
00158 if ((fp = fopen(PROC_IPCHAINS_FILE, "r")) == NULL)
00159 return (-1);
00160
00161 while (fgets(buf, sizeof(buf), fp) != NULL) {
00162 if (sscanf(buf,
00163 "%8s %X/%X->%X/%X %s %hX %hX %hu %u %u %u %u "
00164 "%hu-%hu %hu-%hu A%X X%X %hX %u %hu %s\n",
00165 fwc.fwc_label,
00166 &fwc.fwc_rule.ipfw.fw_src.s_addr,
00167 &fwc.fwc_rule.ipfw.fw_smsk.s_addr,
00168 &fwc.fwc_rule.ipfw.fw_dst.s_addr,
00169 &fwc.fwc_rule.ipfw.fw_dmsk.s_addr,
00170 fwc.fwc_rule.ipfw.fw_vianame,
00171 &fwc.fwc_rule.ipfw.fw_flg,
00172 &fwc.fwc_rule.ipfw.fw_invflg,
00173 &fwc.fwc_rule.ipfw.fw_proto,
00174 &phi, &plo, &bhi, &blo,
00175 &fwc.fwc_rule.ipfw.fw_spts[0],
00176 &fwc.fwc_rule.ipfw.fw_spts[1],
00177 &fwc.fwc_rule.ipfw.fw_dpts[0],
00178 &fwc.fwc_rule.ipfw.fw_dpts[1],
00179 &tand, &txor,
00180 &fwc.fwc_rule.ipfw.fw_redirpt,
00181 &fwc.fwc_rule.ipfw.fw_mark,
00182 &fwc.fwc_rule.ipfw.fw_outputsize,
00183 fwc.fwc_rule.label) != 23)
00184 break;
00185
00186 if (strcmp(fwc.fwc_rule.label, IP_FW_LABEL_ACCEPT) != 0 &&
00187 strcmp(fwc.fwc_rule.label, IP_FW_LABEL_BLOCK) != 0 &&
00188 strcmp(fwc.fwc_rule.label, IP_FW_LABEL_REJECT) != 0)
00189 continue;
00190 if (strcmp(fwc.fwc_label, IP_FW_LABEL_INPUT) != 0 &&
00191 strcmp(fwc.fwc_label, IP_FW_LABEL_OUTPUT) != 0)
00192 continue;
00193 if (strcmp(fwc.fwc_rule.label, "-") == 0)
00194 (fwc.fwc_rule.label)[0] = '\0';
00195 if (strcmp(fwc.fwc_rule.ipfw.fw_vianame, "-") == 0)
00196 (fwc.fwc_rule.ipfw.fw_vianame)[0] = '\0';
00197 fwc.fwc_rule.ipfw.fw_src.s_addr =
00198 htonl(fwc.fwc_rule.ipfw.fw_src.s_addr);
00199 fwc.fwc_rule.ipfw.fw_dst.s_addr =
00200 htonl(fwc.fwc_rule.ipfw.fw_dst.s_addr);
00201 fwc.fwc_rule.ipfw.fw_smsk.s_addr =
00202 htonl(fwc.fwc_rule.ipfw.fw_smsk.s_addr);
00203 fwc.fwc_rule.ipfw.fw_dmsk.s_addr =
00204 htonl(fwc.fwc_rule.ipfw.fw_dmsk.s_addr);
00205
00206 fwc_to_fr(&fwc, &fr);
00207
00208 if ((ret = callback(&fr, arg)) != 0) {
00209 fclose(fp);
00210 return (ret);
00211 }
00212 }
00213 fclose(fp);
00214
00215 return (0);
00216 }
00217
00218 fw_t *
00219 fw_close(fw_t *fw)
00220 {
00221 if (fw != NULL) {
00222 if (fw->fd >= 0)
00223 close(fw->fd);
00224 free(fw);
00225 }
00226 return (NULL);
00227 }