class Nat: """ Represents a Network Address Translation rule. """ def __init__(self, client, server, ip, port, dport, dir, loginfo): """ Create a new NAT rule client -- clients allowed to access this NAT rule server -- host nick the NAT is applied to ip -- IP that is used in NAT port -- Ports that are used in NAT dport -- Destination port for single port redirections dir -- incoming, outgoing or bidirecitonal NAT Note that the NAT is always applied to the "server" host, the UI accessible function is responsible to eventually exchange client and server for "outgoing" NATs (where the naming of client, server makes more sense the other way, think of workstations accessing web server via a NAT) """ if server == "": raise PyromanException("Nat lacking a server host (client: %s, server: %s, ip: %s) at %s" % (client, server, ip, loginfo)) if ip == "": raise PyromanException("Nat lacking IP address: (client: %s, server: %s) at %s" % (client, server, loginfo)) if dir not in ["in", "out", "both"]: raise PyromanException("Nat with invalid direction: (client: %s, server: %s, ip: %s, dir: %s) at %s" % (client, server, ip, dir, loginfo)) if not Util.verify_ip4(ip): raise PyromanException("Nat with invalid IP address: (client: %s, server: %s, ip: %s) at %s" % (client, server, ip, loginfo)) if port: try: self.port = Port(port) except PortInvalidSpec: raise PyromanException("Nat port specification invalid: (client: %s, server: %s, ip: %s, port: %s) at %s " % (client, server, ip, port, loginfo)) if not self.port.forIPv4(): raise PyromanException("Non-IPv4 port specified: "+port) else: self.port = None if dport: try: self.dport = Port(dport) except PortInvalidSpec: raise PyromanException("Nat dport specification invalid: (client: %s, server: %s, ip: %s, port: %s, dport: %s) at %s " % (client, server, ip, port, dport, loginfo)) if not self.dport.forIPv4(): raise PyromanException("Non-IPv4 port specified: "+dport) else: self.dport = None if self.dport and not (self.port.proto == self.dport.proto): raise PyromanException("Nat ports have different protocols: (client: %s, server: %s, ip: %s, port: %s, dport: %s) at %s" % (client, server, ip, port, dport, loginfo)) if dport and not port: raise PyromanException("Nat with destination port, but no source port: (client: %s, server: %s, ip: %s, dport: %s) at %s" % (client, server, ip, dport, loginfo)) self.client = Util.splitter.split(client) self.server = Util.splitter.split(server) self.ip = ip # port, dport are set above self.dir = dir self.loginfo = loginfo def gen_snat(self, client, server): """ Internal helper function, with client, server objects """ iff = client.iface.get_filter("d") target = "SNAT --to-source %s" % self.ip # do we have a port restriction? pfilter = "" if self.port and self.dport: pfilter = self.dport.get_filter_proto() + " " + self.dport.get_filter_port("s") target = target + ":%s" % self.port.port elif self.port: pfilter = self.port.get_filter_proto() + " " + self.port.get_filter_port("s") c = Firewall.chains["natPOST"] for sip in server.ip: filter = iff[0] + " -s %s" % sip c.append4("%s %s -j %s" % (filter, pfilter, target), self.loginfo) def gen_dnat(self, client, server): """ Internal helper function, with client, server objects """ iff = client.iface.get_filter("s") filter = iff[0] + " -d %s" % self.ip # do we have a port restriction? pfilter = "" if self.port: pfilter = self.port.get_filter_proto() + " " + self.port.get_filter_port("d") c = Firewall.chains["natPRE"] for sip in server.ip: target = "DNAT --to-destination %s" % sip if self.dport: target = target + ":%s" % self.dport.port c.append4("%s %s -j %s" % (filter, pfilter, target), self.loginfo) def generate(self): for c in self.client: for s in self.server: client = Firewall.hosts[c] server = Firewall.hosts[s] # sanity checks, that should be moved to "verify" if not client or not server: raise PyromanException("Client or server not found for NAT defined at %s" % self.loginfo) if client.iface == server.iface: raise PyromanException("client interface and server interface match (i.e. cannot NAT!) for NAT defined at %s" % self.loginfo) if self.dir in ["in", "both"]: self.gen_dnat(client, server) if self.dir in ["out", "both"]: self.gen_snat(client, server)
class Nat: """ Represents a Network Address Translation rule. """ def __init__(self, client, server, ip, port, dport, dir, loginfo): """ Create a new NAT rule client -- clients allowed to access this NAT rule server -- host nick the NAT is applied to ip -- IP that is used in NAT port -- Ports that are used in NAT dport -- Destination port for single port redirections dir -- incoming, outgoing or bidirecitonal NAT Note that the NAT is always applied to the "server" host, the UI accessible function is responsible to eventually exchange client and server for "outgoing" NATs (where the naming of client, server makes more sense the other way, think of workstations accessing web server via a NAT) """ if server == "": raise PyromanException( "Nat lacking a server host (client: %s, server: %s, ip: %s) at %s" % (client, server, ip, loginfo)) if ip == "": raise PyromanException( "Nat lacking IP address: (client: %s, server: %s) at %s" % (client, server, loginfo)) if dir not in ["in", "out", "both"]: raise PyromanException( "Nat with invalid direction: (client: %s, server: %s, ip: %s, dir: %s) at %s" % (client, server, ip, dir, loginfo)) if not Util.verify_ip4(ip): raise PyromanException( "Nat with invalid IP address: (client: %s, server: %s, ip: %s) at %s" % (client, server, ip, loginfo)) if port: try: self.port = Port(port) except PortInvalidSpec: raise PyromanException( "Nat port specification invalid: (client: %s, server: %s, ip: %s, port: %s) at %s " % (client, server, ip, port, loginfo)) if not self.port.forIPv4(): raise PyromanException("Non-IPv4 port specified: " + port) else: self.port = None if dport: try: self.dport = Port(dport) except PortInvalidSpec: raise PyromanException( "Nat dport specification invalid: (client: %s, server: %s, ip: %s, port: %s, dport: %s) at %s " % (client, server, ip, port, dport, loginfo)) if not self.dport.forIPv4(): raise PyromanException("Non-IPv4 port specified: " + dport) else: self.dport = None if self.dport and not (self.port.proto == self.dport.proto): raise PyromanException( "Nat ports have different protocols: (client: %s, server: %s, ip: %s, port: %s, dport: %s) at %s" % (client, server, ip, port, dport, loginfo)) if dport and not port: raise PyromanException( "Nat with destination port, but no source port: (client: %s, server: %s, ip: %s, dport: %s) at %s" % (client, server, ip, dport, loginfo)) self.client = Util.splitter.split(client) self.server = Util.splitter.split(server) self.ip = ip # port, dport are set above self.dir = dir self.loginfo = loginfo def gen_snat(self, client, server): """ Internal helper function, with client, server objects """ iff = client.iface.get_filter("d") target = "SNAT --to-source %s" % self.ip # do we have a port restriction? pfilter = "" if self.port and self.dport: pfilter = self.dport.get_filter_proto( ) + " " + self.dport.get_filter_port("s") target = target + ":%s" % self.port.port elif self.port: pfilter = self.port.get_filter_proto( ) + " " + self.port.get_filter_port("s") c = Firewall.chains["natPOST"] for sip in server.ip: filter = iff[0] + " -s %s" % sip c.append4("%s %s -j %s" % (filter, pfilter, target), self.loginfo) def gen_dnat(self, client, server): """ Internal helper function, with client, server objects """ iff = client.iface.get_filter("s") filter = iff[0] + " -d %s" % self.ip # do we have a port restriction? pfilter = "" if self.port: pfilter = self.port.get_filter_proto( ) + " " + self.port.get_filter_port("d") c = Firewall.chains["natPRE"] for sip in server.ip: target = "DNAT --to-destination %s" % sip if self.dport: target = target + ":%s" % self.dport.port c.append4("%s %s -j %s" % (filter, pfilter, target), self.loginfo) def generate(self): for c in self.client: for s in self.server: client = Firewall.hosts[c] server = Firewall.hosts[s] # sanity checks, that should be moved to "verify" if not client or not server: raise PyromanException( "Client or server not found for NAT defined at %s" % self.loginfo) if client.iface == server.iface: raise PyromanException( "client interface and server interface match (i.e. cannot NAT!) for NAT defined at %s" % self.loginfo) if self.dir in ["in", "both"]: self.gen_dnat(client, server) if self.dir in ["out", "both"]: self.gen_snat(client, server)