/* hlfl * Copyright © 2000-2003 Renaud Deraison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Reference : http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO-7.html */ #include "includes.h" #include "hlfl.h" static FILE *fout; extern int matched_if; /*------------------------------------------------------------------ * Private functions *------------------------------------------------------------------*/ static char *icmp_types(type) char *type; { char *ret = malloc(40 + strlen(type)); memset(ret, 0, 40 + strlen(type)); if (!strlen(type)) return ret; if (!strcmp(type, "echo-reply") || !strcmp(type, "destination-unreachable") || !strcmp(type, "echo-request") || !strcmp(type, "time-exceeded") || !strcmp(type, "source-quench") || !strcmp(type, "parameter-problem")) sprintf(ret, "--icmp-type %s", type); else fprintf(stderr, "Warning. Unknown icmp type '%s'\n", type); return ret; } static char *netfilter_sports(ports) char *ports; { if (!ports || !strlen(ports)) return strdup(""); else { char *ret = malloc(20 + strlen(ports)); sprintf(ret, "--source-port %s", ports); return ret; } } static char *netfilter_dports(ports) char *ports; { if (!ports || !strlen(ports)) return strdup(""); else { char *ret = malloc(20 + strlen(ports)); sprintf(ret, "--destination-port %s", ports); return ret; } } /*------------------------------------------------------------------ * Linux netfilter *------------------------------------------------------------------*/ int translate_linux_netfilter(op, proto, src, log, dst, sports, dports, interface) int op; char *proto; char *src; int log; char *dst; char *sports; char *dports; char *interface; { char *via_in = strdup(""); char *via_out = strdup(""); char *t; char *sports_as_src = NULL; char *sports_as_dst = NULL; char *dports_as_src = NULL; char *dports_as_dst = NULL; char *icmp_code = NULL; char *logit = ""; char *rejectit = ""; if (!strcmp(proto, "tcp")) rejectit = "--reject-with tcp-reset"; if (log) { logit = "LOG_"; rejectit = ""; } if (icmp(proto)) { if (sports && strlen(sports)) icmp_code = icmp_types(sports); else if (dports && strlen(dports)) icmp_code = icmp_types(dports); else icmp_code = icmp_types(""); dports_as_src = dports_as_dst = icmp_code; sports_as_src = sports_as_dst = ""; } else { while ((t = strchr(sports, '-'))) t[0] = ':'; while ((t = strchr(dports, '-'))) t[0] = ':'; sports_as_src = netfilter_sports(sports); sports_as_dst = netfilter_dports(sports); dports_as_src = netfilter_sports(dports); dports_as_dst = netfilter_dports(dports); } if (interface) { via_in = malloc(18 + strlen(interface)); sprintf(via_in, "--in-interface %s", interface); via_out = malloc(19 + strlen(interface)); sprintf(via_out, "--out-interface %s", interface); } switch (op) { /* iptables reads the INPUT rules only for packets directed to the system an OUTPUT for packets generated by the system. So the rules would work ok. For a "host firewall" but not for a "router firewall". To assure that it will work under both circumstances, a user-defined chain is created (called ALL) where all the rules are placed, and the default chains will jump to it, this means that both situations will behave exactly the same. It is not the most efficient way to do it, but it isn't the worst possible. It is far better and nicer than just duplicating all the rules for INPUT and OUTPUT in the FORWARD chain. Carlos */ case ACCEPT_ONE_WAY: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sACCEPT %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, via_out); break; case ACCEPT_ONE_WAY_REVERSE: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sACCEPT %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, via_in); break; case ACCEPT_TWO_WAYS: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sACCEPT %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, via_out); fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sACCEPT %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, via_in); break; case ACCEPT_TWO_WAYS_ESTABLISHED: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sACCEPT %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, via_out); fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --match state\ --state ESTABLISHED --jump %sACCEPT %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, via_in); break; case ACCEPT_TWO_WAYS_ESTABLISHED_REVERSE: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sACCEPT %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, via_in); fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --match state\ --state ESTABLISHED --jump %sACCEPT %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, via_out); break; case DENY_ALL: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sDROP %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, via_out); fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sDROP %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, via_in); break; case REJECT_ALL: /* Add extra rules specific to tcp protocol, when protocol is all */ if (!strcmp(proto, "all")) { fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol tcp %s %s --jump %sREJECT --reject-with tcp-reset %s\n", src, dst, sports_as_src, dports_as_dst, logit, via_out); fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol tcp %s %s --jump %sREJECT --reject-with tcp-reset %s\n", dst, src, dports_as_src, sports_as_dst, logit, via_in); } fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sREJECT %s %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, rejectit, via_out); fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sREJECT %s %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, rejectit, via_in); break; case DENY_OUT: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sDROP %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, via_out); break; case DENY_IN: fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sDROP %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, via_in); break; case REJECT_OUT: /* Add an extra rule specific to tcp protocol, when protocol is all */ if (!strcmp(proto, "all")) { fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol tcp %s %s --jump %sREJECT --reject-with tcp-reset %s\n", src, dst, sports_as_src, dports_as_dst, logit, via_out); } fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sREJECT %s %s\n", src, dst, proto, sports_as_src, dports_as_dst, logit, rejectit, via_out); break; case REJECT_IN: /* Add an extra rule specific to tcp protocol, when protocol is all */ if (!strcmp(proto, "all")) { fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol tcp %s %s --jump %sREJECT %s\n", dst, src, dports_as_src, sports_as_dst, logit, via_out); } fprintf(fout, "$iptables --append ALL --source %s --destination %s --protocol %s %s %s --jump %sREJECT %s %s\n", dst, src, proto, dports_as_src, sports_as_dst, logit, rejectit, via_in); break; } if (icmp(proto)) { free(icmp_code); } else { free(sports_as_src); free(sports_as_dst); free(dports_as_src); free(dports_as_dst); } free(via_in); free(via_out); return 0; } int translate_linux_netfilter_start(FILE * output_file) { fout = output_file; fprintf(fout, "#!/bin/sh\n"); fprintf(fout, "# Firewall rules generated by hlfl\n\n"); fprintf(fout, "iptables=\"/sbin/iptables\"\n\n"); fprintf(fout, "$iptables --flush\n"); fprintf(fout, "$iptables --delete-chain\n\n"); fprintf(fout, "# All the rules will be appended to the user-defined chain\n"); fprintf(fout, "# ALL, and the default chains will jump to it.\n"); fprintf(fout, "$iptables --new-chain ALL\n"); fprintf(fout, "$iptables --append INPUT --jump ALL\n"); fprintf(fout, "$iptables --append OUTPUT --jump ALL\n"); fprintf(fout, "$iptables --append FORWARD --jump ALL\n"); /* This probably could be improved, so that if logging is not used, this chains are never created... but for the moment is easier to do it like this, plus I really doubt that unused chains really add significant overhead during use (I haven't seen it) Carlos PS: putting it in the translate function doesn't work, it will create unusable output files if logging is used in more than one rule, since it will attempt to create already existing chains, and there is no really easy way to determine if other rules use logging same as it is not possible to know here if logging will be used. */ fprintf(fout, "# This is intended to suppor logging, still hasn't been\n"); fprintf(fout, "# well tested. It simply SEEMS to work.\n"); fprintf(fout, "$iptables --new-chain LOG_ACCEPT\n"); fprintf(fout, "$iptables --append LOG_ACCEPT --jump LOG --log-level %s \ --log-prefix %s\n", HLFL_LINUX_netfilter_LOG_LEVEL, HLFL_LINUX_netfilter_LOG_PREFIX); fprintf(fout, "$iptables --append LOG_ACCEPT --jump ACCEPT\n"); fprintf(fout, "$iptables --new-chain LOG_DROP\n"); fprintf(fout, "$iptables --append LOG_DROP --jump LOG --log-level %s \ --log-prefix %s\n", HLFL_LINUX_netfilter_LOG_LEVEL, HLFL_LINUX_netfilter_LOG_PREFIX); fprintf(fout, "$iptables --append LOG_DROP --jump DROP\n"); fprintf(fout, "$iptables --new-chain LOG_REJECT\n"); fprintf(fout, "$iptables --append LOG_REJECT --jump LOG --log-level %s \ --log-prefix %s\n", HLFL_LINUX_netfilter_LOG_LEVEL, HLFL_LINUX_netfilter_LOG_PREFIX); fprintf(fout, "$iptables --append LOG_REJECT --protocol tcp --jump REJECT \ --reject-with tcp-reset\n"); fprintf(fout, "$iptables --append LOG_REJECT --jump REJECT\n\n"); return 0; } void print_comment_netfilter(buffer) char *buffer; { fprintf(fout, "#%s", buffer); } void include_text_netfilter(c) char *c; { if (!strncmp("if(", c, 3)) { if (!strncmp("if(netfilter)", c, strlen("if(netfilter)"))) { fprintf(fout, "%s", c + strlen("if(netfilter)")); matched_if = 1; } else matched_if = 0; } else fprintf(fout, "%s", c); }