WvStreams
wvipfirewall.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvIPFirewall is an extremely simple hackish class that handles the Linux
00006  * 2.4 "iptables" firewall.  See wvipfirewall.h.
00007  */
00008 #include "wvipfirewall.h"
00009 #include "wvinterface.h"
00010 #include <unistd.h>
00011 
00012 
00013 bool WvIPFirewall::enable = false, WvIPFirewall::ignore_errors = true;
00014 
00015 
00016 WvIPFirewall::WvIPFirewall() : log("Firewall", WvLog::Debug2)
00017 {
00018     // don't change any firewall rules here!  Remember that there may be
00019     // more than one instance of the firewall object.
00020 }
00021 
00022 
00023 WvIPFirewall::~WvIPFirewall()
00024 {
00025     zap();
00026 }
00027 
00028 
00029 WvString WvIPFirewall::port_command(const char *cmd, const char *proto,
00030                                     const WvIPPortAddr &addr)
00031 {
00032     WvIPAddr ad(addr), none;
00033     
00034     return WvString("iptables %s Services -j ACCEPT -p %s "
00035                     "%s --dport %s "
00036                     "%s",
00037                     cmd, proto,
00038                     ad == none ? WvString("") : WvString("-d %s", ad),
00039                     addr.port,
00040                     shutup());
00041 }
00042 
00043 
00044 WvString WvIPFirewall::redir_command(const char *cmd, const WvIPPortAddr &src,
00045                                      int dstport)
00046 {
00047     WvIPAddr ad(src), none;
00048     
00049     return WvString("iptables -t nat %s TProxy "
00050                     "-p tcp %s --dport %s "
00051                     "-j REDIRECT --to-ports %s "
00052                     "%s",
00053                     cmd,
00054                     ad == none ? WvString("") : WvString("-d %s", ad),
00055                     src.port, dstport,
00056                     shutup());
00057 }
00058 
00059 WvString WvIPFirewall::forward_command(const char *cmd, 
00060                                        const char *proto,
00061                                        const WvIPPortAddr &src,
00062                                        const WvIPPortAddr &dst, bool snat)
00063 {
00064     WvIPAddr srcaddr(src), dstaddr(dst), zero;
00065     WvString haveiface(""), haveoface("");
00066     if (!(srcaddr == zero))
00067     {
00068         haveiface.append("-d ");
00069         haveiface.append((WvString)srcaddr);
00070     }
00071     
00072     WvString retval;
00073 
00074     if ((dst == WvIPAddr("127.0.0.1")) || (dst == zero))
00075     {
00076         retval.append("iptables -t nat %s FASTFORWARD -p %s --dport %s %s "
00077                   "-j REDIRECT --to-port %s %s \n",
00078                    cmd, proto, src.port, haveiface, dst.port, shutup());
00079     }
00080     else
00081     {
00082         haveoface.append("-d ");
00083         haveoface.append((WvString)dstaddr);
00084     
00085         retval.append("iptables -t nat %s FASTFORWARD -p %s --dport %s %s "
00086                   "-j DNAT --to-destination %s "
00087                   "%s \n", cmd, proto, src.port, haveiface,  dst, shutup());
00088     }
00089 
00090     // FA57 is leet-speak for FAST, which is short for FASTFORWARD --adewhurst
00091     // FA58 is FA57+1. Nothing creative sprang to mind. --adewhurst
00092     // 
00093     // We need this to mark the packet as it comes in so that we allow the
00094     // FastForward-ed packets to bypass the firewall (FA57).
00095     // 
00096     // If we mark the packet with FA58, that means it gets masqueraded before
00097     // leaving, which may be useful to work around some network configuratios.
00098     retval.append("iptables -t mangle %s FASTFORWARD -p %s --dport %s "
00099                   "-j MARK --set-mark %s %s %s\n", cmd, proto, src.port,
00100                   snat ? "0xFA58" : "0xFA57", haveiface, shutup());
00101 
00102     // Don't open the port completely; just open it for the forwarded packets
00103     retval.append("iptables %s FFASTFORWARD -j ACCEPT -p %s "
00104                   "--dport %s -m mark --mark %s %s %s\n", cmd, proto, dst.port,
00105                   snat ? "0xFA58" : "0xFA57", haveoface, shutup());
00106     
00107     return retval;
00108 }
00109 
00110 WvString WvIPFirewall::redir_port_range_command(const char *cmd,
00111         const WvIPPortAddr &src_min, const WvIPPortAddr &src_max, int dstport)
00112 {
00113     WvIPAddr ad(src_min), none;
00114     
00115     return WvString("iptables -t nat %s TProxy "
00116                     "-p tcp %s --dport %s:%s "
00117                     "-j REDIRECT --to-ports %s "
00118                     "%s",
00119                     cmd,
00120                     ad == none ? WvString("") : WvString("-d %s", ad),
00121                     src_min.port == 0? WvString(""): WvString(src_min.port),
00122                     src_max.port == 0? WvString(""): WvString(src_max.port),
00123                     dstport,
00124                     shutup());
00125 }
00126 
00127 WvString WvIPFirewall::redir_all_command(const char *cmd, int dstport)
00128 {
00129     return WvString("iptables -t nat %s TProxy "
00130                     "-p tcp "
00131                     "-j REDIRECT --to-ports %s "
00132                     "%s",
00133                     cmd,
00134                     dstport,
00135                     shutup());
00136 }
00137 
00138 WvString WvIPFirewall::proto_command(const char *cmd, const char *proto)
00139 {
00140     return WvString("iptables %s Services -p %s -j ACCEPT "
00141                     "%s",
00142                     cmd, proto, shutup());
00143 }
00144 
00145 
00146 void WvIPFirewall::add_port(const WvIPPortAddr &addr)
00147 {
00148     addrs.append(new WvIPPortAddr(addr), true);
00149     WvString s(port_command("-A", "tcp", addr)),
00150             s2(port_command("-A", "udp", addr));
00151     if (enable)
00152     {
00153         system(s);
00154         system(s2);
00155     }
00156 }
00157 
00158 
00159 // note!  This does not remove the address from the list, only the kernel!
00160 void WvIPFirewall::del_port(const WvIPPortAddr &addr)
00161 {
00162     WvIPPortAddrList::Iter i(addrs);
00163     for (i.rewind(); i.next(); )
00164     {
00165         if (*i == addr)
00166         {
00167             WvString s(port_command("-D", "tcp", addr)),
00168                     s2(port_command("-D", "udp", addr));
00169             if (enable)
00170             {
00171                 system(s);
00172                 system(s2);
00173             }
00174             return;
00175         }
00176     }
00177 }
00178 
00179 void WvIPFirewall::add_forward(const WvIPPortAddr &src,
00180                                const WvIPPortAddr &dst, bool snat)
00181 {
00182     ffwds.append(new FFwd(src, dst, snat), true);
00183     WvString s(forward_command("-A", "tcp", src, dst, snat)),
00184             s2(forward_command("-A", "udp", src, dst, snat));
00185 
00186     log("Add Forwards (%s):\n%s\n%s\n", enable, s, s2);
00187     
00188     if (enable)
00189     {
00190         system(s);
00191         system(s2);
00192     }
00193 }
00194 
00195 void WvIPFirewall::del_forward(const WvIPPortAddr &src,
00196                                const WvIPPortAddr &dst, bool snat)
00197 {
00198     FFwdList::Iter i(ffwds);
00199     for (i.rewind(); i.next();) 
00200     {
00201         if (i->src == src && i->dst == dst && i->snat == snat) 
00202         {
00203             WvString s(forward_command("-D", "tcp", src, dst, snat)),
00204                     s2(forward_command("-D", "udp", src, dst, snat));
00205 
00206             log("Delete Forward (%s):\n%s\n%s\n", enable, s, s2);
00207     
00208             if (enable) 
00209             {
00210                 system(s);
00211                 system(s2);
00212             }
00213         }
00214     }
00215 }
00216 
00217 void WvIPFirewall::add_redir(const WvIPPortAddr &src, int dstport)
00218 {
00219     redirs.append(new Redir(src, dstport), true);
00220     WvString s(redir_command("-A", src, dstport));
00221     if (enable) system(s);
00222 }
00223 
00224 
00225 void WvIPFirewall::del_redir(const WvIPPortAddr &src, int dstport)
00226 {
00227     RedirList::Iter i(redirs);
00228     for (i.rewind(); i.next(); )
00229     {
00230         if (i->src == src && i->dstport == dstport)
00231         {
00232             WvString s(redir_command("-D", src, dstport));
00233             if (enable) system(s);
00234             return;
00235         }
00236     }
00237 }
00238 
00239 void WvIPFirewall::add_redir_all(int dstport)
00240 {
00241     redir_alls.append(new RedirAll(dstport), true);
00242     WvString s(redir_all_command("-A", dstport));
00243     if (enable) system(s);
00244 }
00245 
00246 
00247 void WvIPFirewall::del_redir_all(int dstport)
00248 {
00249     RedirAllList::Iter i(redir_alls);
00250     for (i.rewind(); i.next(); )
00251     {
00252         if (i->dstport == dstport)
00253         {
00254             WvString s(redir_all_command("-D", dstport));
00255             if (enable) system(s);
00256             return;
00257         }
00258     }
00259 }
00260 
00261 void WvIPFirewall::add_redir_port_range(const WvIPPortAddr &src_min,
00262         const WvIPPortAddr &src_max, int dstport)
00263 {
00264     redir_port_ranges.append(new RedirPortRange(src_min, src_max, dstport), true);
00265     WvString s(redir_port_range_command("-A", src_min, src_max, dstport));
00266     if (enable) system(s);
00267 }
00268 
00269 
00270 void WvIPFirewall::del_redir_port_range(const WvIPPortAddr &src_min,
00271         const WvIPPortAddr &src_max, int dstport)
00272 {
00273     RedirPortRangeList::Iter i(redir_port_ranges);
00274     for (i.rewind(); i.next(); )
00275     {
00276         if (i->src_min == src_min && i->src_max == src_max
00277                 && i->dstport == dstport)
00278         {
00279             WvString s(redir_port_range_command("-D", src_min, src_max, dstport));
00280             if (enable) system(s);
00281             return;
00282         }
00283     }
00284 }
00285 
00286 
00287 void WvIPFirewall::add_proto(WvStringParm proto)
00288 {
00289     protos.append(new WvString(proto), true);
00290     WvString s(proto_command("-A", proto));
00291     if (enable) system(s);
00292 }
00293 
00294 
00295 void WvIPFirewall::del_proto(WvStringParm proto)
00296 {
00297     WvStringList::Iter i(protos);
00298     for (i.rewind(); i.next(); )
00299     {
00300         if (*i == proto)
00301         {
00302             WvString s(proto_command("-D", proto));
00303             if (enable) system(s);
00304             return;
00305         }
00306     }
00307 }
00308 
00309 
00310 // clear out our portion of the firewall
00311 void WvIPFirewall::zap()
00312 {
00313     WvIPPortAddrList::Iter i(addrs);
00314     for (i.rewind(); i.next(); )
00315     {
00316         del_port(*i);
00317         i.xunlink();
00318     }
00319 
00320     FFwdList::Iter ifwd(ffwds);
00321     for (ifwd.rewind(); ifwd.next();)
00322     {
00323         del_forward(ifwd->src, ifwd->dst, ifwd->snat);
00324         ifwd.xunlink();
00325     }
00326     
00327     RedirList::Iter i2(redirs);
00328     for (i2.rewind(); i2.next(); )
00329     {
00330         del_redir(i2->src, i2->dstport);
00331         i2.xunlink();
00332     }
00333     
00334     RedirAllList::Iter i2_5(redir_alls);
00335     for (i2_5.rewind(); i2_5.next(); )
00336     {
00337         del_redir_all(i2_5->dstport);
00338         i2_5.xunlink();
00339     }
00340     
00341     RedirPortRangeList::Iter port_range(redir_port_ranges);
00342     for (port_range.rewind(); port_range.next(); )
00343     {
00344         del_redir_port_range(port_range->src_min, port_range->src_max,
00345                 port_range->dstport);
00346         port_range.xunlink();
00347     }
00348     
00349     WvStringList::Iter i3(protos);
00350     for (i3.rewind(); i3.next(); )
00351     {
00352         del_proto(*i3);
00353         i3.xunlink();
00354     }
00355 }