00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "config.h"
00011
00012 #include <iphlpapi.h>
00013
00014 #include <ctype.h>
00015 #include <errno.h>
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019
00020 #include "dnet.h"
00021
00022 #define PKTFILTER_PIPE "\\\\.\\pipe\\PktFltPipe"
00023 #define MAX_RULE_LENGTH 256
00024
00025 #define FILTER_FAILURE 0
00026 #define FILTER_SUCCESS 1
00027 #define FILTER_MESSAGE 2
00028
00029 char *icmp_types[] = {
00030 "echorep",
00031 "",
00032 "",
00033 "unreach",
00034 "squench",
00035 "redir",
00036 "",
00037 "",
00038 "echo",
00039 "router_adv",
00040 "router_sol",
00041 "timex",
00042 "paramprob",
00043 "timest",
00044 "timestrep",
00045 "inforeq",
00046 "inforep",
00047 "maskreq",
00048 "maskrep",
00049 NULL
00050 };
00051
00052 struct fw_handle {
00053 IP_ADAPTER_INFO *ifinfo;
00054
00055 };
00056
00057 static int
00058 parse_addr(char *p, struct addr *a)
00059 {
00060 if (strcmp(p, "any") == 0)
00061 return (addr_aton("0.0.0.0/0", a));
00062 return (addr_aton(p, a));
00063 }
00064
00065 static int
00066 parse_portspec(char *str, uint16_t *ports)
00067 {
00068 char *p = strsep(&str, " ");
00069
00070 if (p[0] == '=') {
00071 ports[0] = ports[1] = atoi(strsep(&str, " "));
00072 } else if (p[0] == '<') {
00073 ports[1] = atoi(strsep(&str, " "));
00074 if (p[1] != '=') ports[1]--;
00075 } else if (p[0] == '>') {
00076 ports[1] = TCP_PORT_MAX;
00077 ports[0] = atoi(strsep(&str, " "));
00078 if (p[1] != '=') ports[0]++;
00079 } else if (p[0] != '\0') {
00080 if (strcmp(strsep(&str, " "), "><") != 0)
00081 return (-1);
00082 ports[0] = atoi(p) + 1;
00083 ports[1] = atoi(strsep(&str, " ")) - 1;
00084 }
00085 return (0);
00086 }
00087
00088 static int
00089 parse_icmpspec(char *str, uint16_t *type, uint16_t *code)
00090 {
00091 char *p, *e;
00092 int i;
00093
00094 p = strsep(&str, " ");
00095 for (i = 0; icmp_types[i] && strcmp(p, icmp_types[i]); i++)
00096 ;
00097 if (icmp_types[i] == NULL) {
00098 i = strtol(p, &e, 10);
00099 if (*e != '\0')
00100 return (-1);
00101 }
00102 type[0] = i;
00103 type[1] = 0xff;
00104
00105 p = strsep(&str, " ");
00106 if (p != NULL && strcmp(p, "code")) {
00107 p = strsep(&str, " ");
00108 i = strtol(p, &e, 10);
00109 if (*e != '\0')
00110 return (-1);
00111 code[0] = i;
00112 code[1] = 0xff;
00113 }
00114 return (0);
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124 static int
00125 parse_rule(char *str, struct fw_rule *rule)
00126 {
00127 char *p, *q;
00128
00129 memset(rule, 0, sizeof(*rule));
00130
00131
00132 p = strsep(&str, " ");
00133 if (strcmp(p, "block") == 0)
00134 rule->fw_op = FW_OP_BLOCK;
00135 else if (strcmp(p, "pass") == 0)
00136 rule->fw_op = FW_OP_ALLOW;
00137 else return (-1);
00138
00139
00140 p = strsep(&str, " ");
00141 if (strcmp(p, "in") == 0)
00142 rule->fw_dir = FW_DIR_IN;
00143 else if (strcmp(p, "out") == 0)
00144 rule->fw_dir = FW_DIR_OUT;
00145 else return (-1);
00146
00147
00148 if (strcmp(strsep(&str, " "), "on") != 0)
00149 return (-1);
00150 p = strsep(&str, " ");
00151
00152 if ((q = strstr(p, "proto")) != NULL)
00153 *q = '\0';
00154 if (strcmp(p, "all") != 0)
00155 strlcpy(rule->fw_device, p, sizeof(rule->fw_device));
00156
00157
00158 p = strsep(&str, " ");
00159
00160 if (strcmp(p, "proto") == 0)
00161 p = strsep(&str, " ");
00162
00163 if (strcmp(p, "all") == 0)
00164 return (0);
00165 if (strcmp(p, "icmp") == 0)
00166 rule->fw_proto = IP_PROTO_ICMP;
00167 else if (strcmp(p, "tcp") == 0)
00168 rule->fw_proto = IP_PROTO_TCP;
00169 else if (strcmp(p, "udp") == 0)
00170 rule->fw_proto = IP_PROTO_UDP;
00171 else rule->fw_proto = atoi(p);
00172
00173
00174 p = strsep(&str, " ");
00175 if (strcmp(p, "all") == 0)
00176 return (0);
00177 if (strcmp(p, "from") != 0)
00178 goto icmp_type_code;
00179 p = strsep(&str, " ");
00180 if (parse_addr(p, &rule->fw_src) < 0)
00181 return (-1);
00182
00183
00184 p = strsep(&str, " ");
00185 if (strcmp(p, "port") == 0) {
00186 if ((p = strstr(str, " to ")) == NULL)
00187 return (-1);
00188 *p++ = '\0';
00189 if (parse_portspec(str, rule->fw_sport) < 0)
00190 return (-1);
00191 str = p + 3;
00192 } else if (strcmp(p, "to") != 0)
00193 return (-1);
00194
00195
00196 p = strsep(&str, " ");
00197 if (parse_addr(p, &rule->fw_dst) < 0)
00198 return (-1);
00199
00200
00201 p = strsep(&str, " ");
00202 if (strcmp(p, "port") == 0)
00203 return (parse_portspec(str, rule->fw_dport));
00204
00205 icmp_type_code:
00206
00207 if (strcmp(p, "icmp-type") == 0) {
00208 if (parse_icmpspec(str, rule->fw_sport, rule->fw_dport) < 0)
00209 return (-1);
00210 }
00211 return (0);
00212 }
00213
00214 static int
00215 format_rule(const struct fw_rule *rule, char *buf, int len)
00216 {
00217 char tmp[128];
00218
00219 strlcpy(buf, (rule->fw_op == FW_OP_ALLOW) ? "pass " : "block ", len);
00220 strlcat(buf, (rule->fw_dir == FW_DIR_IN) ? "in " : "out ", len);
00221 snprintf(tmp, sizeof(tmp), "on %s ", rule->fw_device);
00222 strlcat(buf, tmp, len);
00223 if (rule->fw_proto != 0) {
00224 snprintf(tmp, sizeof(tmp), "proto %d ", rule->fw_proto);
00225 strlcat(buf, tmp, len);
00226 }
00227
00228 if (rule->fw_src.addr_type != ADDR_TYPE_NONE) {
00229 snprintf(tmp, sizeof(tmp), "from %s ",
00230 addr_ntoa(&rule->fw_src));
00231 strlcat(buf, tmp, len);
00232 } else
00233 strlcat(buf, "from any ", len);
00234
00235
00236 if (rule->fw_proto == IP_PROTO_TCP || rule->fw_proto == IP_PROTO_UDP) {
00237 if (rule->fw_sport[0] == rule->fw_sport[1])
00238 snprintf(tmp, sizeof(tmp), "port = %d ",
00239 rule->fw_sport[0]);
00240 else
00241 snprintf(tmp, sizeof(tmp), "port %d >< %d ",
00242 rule->fw_sport[0] - 1, rule->fw_sport[1] + 1);
00243 strlcat(buf, tmp, len);
00244 }
00245
00246 if (rule->fw_dst.addr_type != ADDR_TYPE_NONE) {
00247 snprintf(tmp, sizeof(tmp), "to %s ",
00248 addr_ntoa(&rule->fw_dst));
00249 strlcat(buf, tmp, len);
00250 } else
00251 strlcat(buf, "to any ", len);
00252
00253
00254 if (rule->fw_proto == IP_PROTO_TCP || rule->fw_proto == IP_PROTO_UDP) {
00255 if (rule->fw_dport[0] == rule->fw_dport[1])
00256 snprintf(tmp, sizeof(tmp), "port = %d",
00257 rule->fw_dport[0]);
00258 else
00259 snprintf(tmp, sizeof(tmp), "port %d >< %d",
00260 rule->fw_dport[0] - 1, rule->fw_dport[1] + 1);
00261 strlcat(buf, tmp, len);
00262 } else if (rule->fw_proto == IP_PROTO_ICMP) {
00263 if (rule->fw_sport[1]) {
00264 snprintf(tmp, sizeof(tmp), "icmp-type %d",
00265 rule->fw_sport[0]);
00266 strlcat(buf, tmp, len);
00267 if (rule->fw_dport[1]) {
00268 snprintf(tmp, sizeof(tmp), " code %d",
00269 rule->fw_dport[0]);
00270 strlcat(buf, tmp, len);
00271 }
00272 }
00273 }
00274 return (strlen(buf));
00275 }
00276
00277 static char *
00278 call_pipe(const char *msg, int len)
00279 {
00280 HANDLE *pipe;
00281 DWORD i;
00282 char *p, *reply, status;
00283
00284 if (!WaitNamedPipe(PKTFILTER_PIPE, NMPWAIT_USE_DEFAULT_WAIT) ||
00285 (pipe = CreateFile(PKTFILTER_PIPE, GENERIC_READ | GENERIC_WRITE,
00286 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
00287 return (NULL);
00288 }
00289 reply = NULL;
00290
00291 if (WriteFile(pipe, msg, len, &i, NULL)) {
00292 if (ReadFile(pipe, &status, sizeof(status), &i, NULL)) {
00293 if (status == FILTER_FAILURE) {
00294 ReadFile(pipe, &status, sizeof(status),
00295 &i, NULL);
00296 } else if (status == FILTER_MESSAGE) {
00297
00298 if (ReadFile(pipe, &len, 4, &i, NULL)) {
00299
00300 p = reply = calloc(1, len + 1);
00301 if (!ReadFile(pipe, reply, len,
00302 &i, NULL)) {
00303 free(reply);
00304 reply = NULL;
00305 }
00306 }
00307 } else if (status == FILTER_SUCCESS)
00308 reply = strdup("");
00309 }
00310 }
00311 CloseHandle(pipe);
00312 return (reply);
00313 }
00314
00315 fw_t *
00316 fw_open(void)
00317 {
00318 fw_t *f;
00319 IP_ADAPTER_INFO *ifinfo;
00320 ULONG size;
00321
00322 if ((f = calloc(1, sizeof(*f))) == NULL)
00323 return (NULL);
00324
00325 size = sizeof(*f->ifinfo);
00326 f->ifinfo = malloc(size);
00327 if (GetAdaptersInfo(f->ifinfo, &size) != ERROR_SUCCESS) {
00328 free(f->ifinfo);
00329 f->ifinfo = malloc(size);
00330 GetAdaptersInfo(f->ifinfo, &size);
00331 }
00332
00333 for (ifinfo = f->ifinfo; ifinfo != NULL; ifinfo = ifinfo->Next) {
00334 char *fmt;
00335 if (ifinfo->Type == MIB_IF_TYPE_ETHERNET)
00336 fmt = "eth";
00337 else if (ifinfo->Type == MIB_IF_TYPE_PPP)
00338 fmt = "ppp";
00339 else if (ifinfo->Type == MIB_IF_TYPE_SLIP)
00340 fmt = "sl";
00341 else if (ifinfo->Type == MIB_IF_TYPE_LOOPBACK)
00342 fmt = "lo";
00343 else if (ifinfo->Type == MIB_IF_TYPE_TOKENRING)
00344 fmt = "tr";
00345 else if (ifinfo->Type == MIB_IF_TYPE_FDDI)
00346 fmt = "fd";
00347 else
00348 fmt = "if";
00349 sprintf(ifinfo->AdapterName, "%s%lu", fmt, ifinfo->ComboIndex);
00350 }
00351 return (f);
00352 }
00353
00354 int
00355 fw_add(fw_t *f, const struct fw_rule *rule)
00356 {
00357 char *p, buf[MAX_RULE_LENGTH];
00358 int len;
00359
00360 len = format_rule(rule, buf, sizeof(buf));
00361
00362 if ((p = call_pipe(buf, len)) == NULL)
00363 return (-1);
00364 free(p);
00365 return (0);
00366 }
00367
00368 int
00369 fw_delete(fw_t *f, const struct fw_rule *rule)
00370 {
00371 struct fw_rule tmp;
00372 char *p, *line, *msg, cmd[128], buf[MAX_RULE_LENGTH];
00373 int n, ruleno, len;
00374
00375 format_rule(rule, buf, sizeof(buf));
00376
00377 len = snprintf(cmd, sizeof(cmd), "List on %s", rule->fw_device);
00378 if ((msg = call_pipe(cmd, len)) == NULL)
00379 return (-1);
00380
00381 for (ruleno = 0, p = msg; (line = strsep(&p, "\r\n")) != NULL; ) {
00382 if (strncmp(line, "rule ", 5) == 0) {
00383 line += 5;
00384 n = atoi(strsep(&line, ":"));
00385 if (parse_rule(line + 1, &tmp) == 0 &&
00386 memcmp(&tmp, rule, sizeof(tmp)) == 0) {
00387 ruleno = n;
00388 break;
00389 }
00390 }
00391 }
00392 free(msg);
00393 if (ruleno == 0) {
00394 errno = ENXIO;
00395 SetLastError(ERROR_NO_DATA);
00396 return (-1);
00397 }
00398 len = snprintf(cmd, sizeof(cmd), "delete %d on %s",
00399 ruleno, rule->fw_device);
00400 if ((p = call_pipe(cmd, len)) == NULL)
00401 return (-1);
00402 free(p);
00403
00404 return (0);
00405 }
00406
00407 int
00408 fw_loop(fw_t *f, fw_handler callback, void *arg)
00409 {
00410 struct fw_rule rule;
00411 IP_ADAPTER_INFO *ifinfo;
00412 char *p, *line, *msg, buf[MAX_RULE_LENGTH];
00413 int len, ret;
00414
00415 for (ret = 0, ifinfo = f->ifinfo; ret == 0 && ifinfo != NULL;
00416 ifinfo = ifinfo->Next) {
00417 len = snprintf(buf, sizeof(buf), "list on %s",
00418 ifinfo->AdapterName);
00419 if ((msg = call_pipe(buf, len)) == NULL)
00420 return (-1);
00421
00422
00423 for (p = msg; (line = strsep(&p, "\r\n")) != NULL; ) {
00424 if (*line == '\0' || *line == '#' || isspace(*line))
00425 continue;
00426 if (parse_rule(line, &rule) == 0) {
00427 if ((ret = callback(&rule, arg)) != 0)
00428 break;
00429 }
00430 }
00431 free(msg);
00432 }
00433 return (ret);
00434 }
00435
00436 fw_t *
00437 fw_close(fw_t *f)
00438 {
00439 if (f != NULL) {
00440 free(f->ifinfo);
00441 free(f);
00442 }
00443 return (NULL);
00444 }