def __init__(self, protocol=ZD_PROTO_AUTO, timeout_connect=None, timeout_state=None): """<method maturity="stable"> <summary> Constructor to initialize a StateBasedChainer instance. </summary> <description> <para> This constructor initializes a StateBasedChainer class by filling arguments with appropriate values and calling the inherited constructor. </para> </description> <metainfo> <arguments> <argument maturity="stable"> <name>protocol</name> <type> <link id="zorp.proto.id"/> </type> <default>ZD_PROTO_AUTO</default> <description> Optional, specifies connection protocol (<parameter> ZD_PROTO_TCP</parameter> or <parameter>ZD_PROTO_UDP </parameter>), when not specified it defaults to the same protocol used on the client side. </description> </argument> <argument> <name>timeout_connect</name> <type> <integer/> </type> <default>30000</default> <description> Specifies connection timeout to be used when connecting to the target server. </description> </argument> <argument> <name>timeout_state</name> <type> <integer/> </type> <default>60000</default> <description> The down state of remote hosts is kept for this interval in miliseconds. </description> </argument> </arguments> </metainfo> </method> """ super(StateBasedChainer, self).__init__(protocol, timeout_connect) if not timeout_state: timeout_state = 60000 self.state = TimedCache('chainer-state', int((timeout_state + 999) / 1000), update_stamp=FALSE)
def __init__(self, protocol=ZD_PROTO_AUTO, timeout_connect=None, timeout_state=None): """<method maturity="stable"> <summary> Constructor to initialize a StateBasedChainer instance. </summary> <description> <para> This constructor initializes a StateBasedChainer class by filling arguments with appropriate values and calling the inherited constructor. </para> </description> <metainfo> <arguments> <argument maturity="stable"> <name>protocol</name> <type> <link id="zorp.proto.id"/> </type> <default>ZD_PROTO_AUTO</default> <description> Optional, specifies connection protocol (<parameter> ZD_PROTO_TCP</parameter> or <parameter>ZD_PROTO_UDP </parameter>), when not specified it defaults to the same protocol used on the client side. </description> </argument> <argument> <name>timeout_connect</name> <type> <integer/> </type> <default>30000</default> <description> Specifies connection timeout to be used when connecting to the target server. </description> </argument> <argument> <name>timeout_state</name> <type> <integer/> </type> <default>60000</default> <description> The down state of remote hosts is kept for this interval in miliseconds. </description> </argument> </arguments> </metainfo> </method> """ MultiTargetChainer.__init__(self, protocol, timeout_connect) if not timeout_state: timeout_state = 60000 self.state = TimedCache('chainer-state', int((timeout_state + 999) / 1000), update_stamp=FALSE)
class StateBasedChainer(MultiTargetChainer): """<class maturity="stable" abstract="yes"> <summary> Class encapsulating connection establishment with multiple target addresses and keeping down state between connects. </summary> <description> <para> This class encapsulates a real TCP/IP connection establishment, and is used when a top-level proxy wants to perform chaining. In addition to ConnectChainer, this class adds the capability to perform stateful, load balance server connections among a set of IP addresses. </para> <note> <para>Both the <link linkend="python.Chainer.FailoverChainer">FailoverChainer</link> and <link linkend="python.Chainer.RoundRobinChainer">RoundRobinChainer</link> classes are derived from StateBasedChainer.</para> </note> </description> <metainfo> <attributes> <attribute internal="yes"> <name>state</name> <type></type> <description>Down state of target hosts. </description> </attribute> </attributes> </metainfo> </class> """ def __init__(self, protocol=ZD_PROTO_AUTO, timeout_connect=None, timeout_state=None): """<method maturity="stable"> <summary> Constructor to initialize a StateBasedChainer instance. </summary> <description> <para> This constructor initializes a StateBasedChainer class by filling arguments with appropriate values and calling the inherited constructor. </para> </description> <metainfo> <arguments> <argument maturity="stable"> <name>protocol</name> <type> <link id="zorp.proto.id"/> </type> <default>ZD_PROTO_AUTO</default> <description> Optional, specifies connection protocol (<parameter> ZD_PROTO_TCP</parameter> or <parameter>ZD_PROTO_UDP </parameter>), when not specified it defaults to the same protocol used on the client side. </description> </argument> <argument> <name>timeout_connect</name> <type> <integer/> </type> <default>30000</default> <description> Specifies connection timeout to be used when connecting to the target server. </description> </argument> <argument> <name>timeout_state</name> <type> <integer/> </type> <default>60000</default> <description> The down state of remote hosts is kept for this interval in miliseconds. </description> </argument> </arguments> </metainfo> </method> """ MultiTargetChainer.__init__(self, protocol, timeout_connect) if not timeout_state: timeout_state = 60000 self.state = TimedCache('chainer-state', int((timeout_state + 999) / 1000), update_stamp=FALSE) def getNextTarget(self, session): """<method internal="yes"> </method> """ while 1: (target_local, target_remote) = MultiTargetChainer.getNextTarget(self, session) if not target_remote: # we enumerated all targets try: session.chainer_targets_enumerated = session.chainer_targets_enumerated + 1 except AttributeError: session.chainer_targets_enumerated = 1 if not self.state or session.chainer_targets_enumerated == 2: # we enumerated all our targets twice, once # with state held, and then all state # cleared, we were not successful, terminate # target iteration log( None, CORE_MESSAGE, 4, "All destinations are down for two full iterations, giving up;" ) return (None, None) ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log( None, CORE_MESSAGE, 4, "All destinations are down, clearing cache and trying again;" ) # we enumerated all targets, and all of them were # down, clear our state and try once more self.state.clear() self.restart(session) continue is_host_down = self.state.lookup(target_remote.ip_s) if not is_host_down: return (target_local, target_remote) else: ## LOG ## # This message reports that the remote end is down, but Zorp does not store the # down state of the remote end, so Zorp will try to connect to it next time. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, skipping; remote='%s'", (target_remote, )) def disableTarget(self, session, target_local, target_remote): """<method internal="yes"> </method> """ ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, keeping state; remote='%s'", (target_remote, )) self.state.store(target_remote.ip_s, 1)
def __init__(self, server_name, server_port=25, cache_timeout=60, attempt_delivery=FALSE, force_delivery_attempt=FALSE, sender_address='<>', bind_name=''): """<method maturity="stable"> <summary> </summary> <description> </description> <metainfo> <arguments> <argument maturity="stable"> <name>server_name</name> <type> <string/> </type> <description> Domain name of the SMTP server that will verify the addresses. </description> </argument> <argument maturity="stable"> <name>server_port</name> <type> <integer/> </type> <default>25</default> <description> Port of the target server. </description> </argument> <argument maturity="stable"> <name>cache_timeout</name> <type> <integer/> </type> <default>60</default> <description> How long will the result of an address verification be retained (in seconds). </description> </argument> <argument maturity="obsolete"> <name>attempt_delivery</name> <type> <boolean/> </type> <default>FALSE</default> <description> Obsolete, ignored. </description> </argument> <argument maturity="stable"> <name>force_delivery_attempt</name> <type> <boolean/> </type> <default>FALSE</default> <description> Force a delivery attempt even if the autodetection code otherwise would use VRFY. Useful if the server always returns success for VRFY. </description> </argument> <argument maturity="stable"> <name>sender_address</name> <type> <string/> </type> <default>"<>"</default> <description> This value will be used as the mail sender for the attempted mail delivery. Mail delivery is attempted if the <parameter>force_delivery_attempt</parameter> is TRUE, or the recipient server does not support the VRFY command. </description> </argument> <argument maturity="stable"> <name>bind_name</name> <type> <string/> </type> <default>""</default> <description> Specifies the hostname to bind to before initiating the connection to the SMTP server. </description> </argument> </arguments> </metainfo> </method> """ super(SmtpInvalidRecipientMatcher, self).__init__() self.force_delivery_attempt = force_delivery_attempt self.server_name = server_name self.server_port = server_port self.bind_name = bind_name self.sender_address = sender_address self.cache = TimedCache('smtp_valid_recipients(%s)' % server_name, cache_timeout)
class SmtpInvalidRecipientMatcher(AbstractMatcher): """<class maturity="stable" type="matcher"> <summary> Class verifying the validity of the recipient addresses in E-mails. </summary> <description> <para> This class encapsulates a VRFY/RCPT based validity checker to transparently verify the existance of E-mail addresses. Instead of immediately sending the e-mail to the recipient SMTP server, Zorp queuries an independent SMTP server about the existance of the recipient e-mail address. </para> <para> Instances of this class can be referred to in the <parameter>recipient_matcher</parameter> attribute of the <link linkend="python.Smtp.SmtpProxy">SmtpProxy</link> class. The SmtpProxy will automatically reject unknown recipients even if the recipient SMTP server would accept them. </para> <example> <title>SmtpInvalidMatcher example</title> <synopsis>Python: class SmtpRecipientMatcherProxy(SmtpProxy): recipient_matcher="SmtpCheckrecipient" def config(self): super(SmtpRecipientMatcherProxy, self).config() MatcherPolicy(name="SmtpCheckrecipient", matcher=SmtpInvalidRecipientMatcher (server_port=25, cache_timeout=60, attempt_delivery=FALSE, force_delivery_attempt=FALSE, server_name="recipientcheck.example.com"))</synopsis> </example> </description> <metainfo> <attributes/> </metainfo> </class> """ def __init__(self, server_name, server_port=25, cache_timeout=60, attempt_delivery=FALSE, force_delivery_attempt=FALSE, sender_address='<>', bind_name=''): """<method maturity="stable"> <summary> </summary> <description> </description> <metainfo> <arguments> <argument maturity="stable"> <name>server_name</name> <type> <string/> </type> <description> Domain name of the SMTP server that will verify the addresses. </description> </argument> <argument maturity="stable"> <name>server_port</name> <type> <integer/> </type> <default>25</default> <description> Port of the target server. </description> </argument> <argument maturity="stable"> <name>cache_timeout</name> <type> <integer/> </type> <default>60</default> <description> How long will the result of an address verification be retained (in seconds). </description> </argument> <argument maturity="obsolete"> <name>attempt_delivery</name> <type> <boolean/> </type> <default>FALSE</default> <description> Obsolete, ignored. </description> </argument> <argument maturity="stable"> <name>force_delivery_attempt</name> <type> <boolean/> </type> <default>FALSE</default> <description> Force a delivery attempt even if the autodetection code otherwise would use VRFY. Useful if the server always returns success for VRFY. </description> </argument> <argument maturity="stable"> <name>sender_address</name> <type> <string/> </type> <default>"<>"</default> <description> This value will be used as the mail sender for the attempted mail delivery. Mail delivery is attempted if the <parameter>force_delivery_attempt</parameter> is TRUE, or the recipient server does not support the VRFY command. </description> </argument> <argument maturity="stable"> <name>bind_name</name> <type> <string/> </type> <default>""</default> <description> Specifies the hostname to bind to before initiating the connection to the SMTP server. </description> </argument> </arguments> </metainfo> </method> """ super(SmtpInvalidRecipientMatcher, self).__init__() self.force_delivery_attempt = force_delivery_attempt self.server_name = server_name self.server_port = server_port self.bind_name = bind_name self.sender_address = sender_address self.cache = TimedCache('smtp_valid_recipients(%s)' % server_name, cache_timeout) def checkMatch(self, email): """<method internal="yes"> </method> """ # email is a fully qualified email address like [email protected] try: cached = self.cache.lookup(email) if cached != None: ## LOG ## # This message reports that the recipient address has been already checked and # Zorp uses the cached information. ## log(None, CORE_DEBUG, 6, "Cached recipient match found; email='%s', cached='%d'", (email, cached)) if cached: return TRUE else: return FALSE except KeyError: cached = None try: ## LOG ## # This message reports that the recipient address has not been already checked and # Zorp is going to check it now directly. ## log(None, CORE_DEBUG, 6, "Recipient validity not cached, trying the direct way; email='%s'", (email)) server = SmtpProto(self.server_name, self.server_port, bind_addr=self.bind_name) try: (smtp_code, smtp_msg) = server.ehlo() if smtp_code > 299: (smtp_code, smtp_msg) = server.helo() esmtp = FALSE else: esmtp = TRUE if smtp_code > 299: raise MatcherException, "Server refused our EHLO/HELO command." present = FALSE smtp_code = -1 if not self.force_delivery_attempt and (not esmtp or server.has_extn("VRFY")): log(None, CORE_DEBUG, 6, "Trying to use VRFY to check email address validity; email='%s'", (email,)) (smtp_code, smtp_msg) = server.verify(email) present = (smtp_code < 300) else: log(None, CORE_DEBUG, 6, "Attempting delivery to check email address validity; email='%s'", (email,)) (smtp_code, smtp_msg) = server.mail(self.sender_address) if smtp_code == 250: (smtp_code, smtp_msg) = server.rcpt(email) present = (smtp_code < 300) else: ## LOG ## # This message indicates that the sender address was rejected during the recipient address # verify check and Zorp rejects the recipient address. ## log(None, CORE_ERROR, 3, "SMTP sender was rejected, unable to verify user existence; email='%s', server_address='%s', server_port='%d'", (email, self.server_name, self.server_port)) raise MatcherException, "Server has not accepted our sender (%s)." % self.sender_address if present: ## LOG ## # This message reports that the recipient address verify was successful and Zorp accepts it. ## log(None, CORE_INFO, 5, "Server accepted recipient; email='%s'", email) # we only cache successful lookups self.cache.store(email, not present) elif smtp_code != -1: ## LOG ## # This message reports that the recipient address verify was unsuccessful and Zorp rejects it. ## log(None, CORE_INFO, 4, "Server rejected recipient; email='%s'", email) finally: server.quit() except (socket.error, smtplib.SMTPException), e: ## LOG ## # This message indicates that an SMTP error occurred during the recipient address verify # and Zorp rejects it. ## log(None, CORE_ERROR, 3, "SMTP error during recipient validity checking; info='%s'", e) raise MatcherException, "SMTP error or socket failure while checking user validity (%s)" % str(e) # we return when we want to reject... return not present
def __init__(self, name=None, timeout=600, update_stamp=TRUE, service_equiv=FALSE, cleanup_threshold=100): """ <method maturity="stable"> <summary> Constructor to initialize an instance of the AuthCache class. </summary> <description> <para> This constructor initializes and registers an AuthCache instance that can be referenced in authentication policies. </para> </description> <metainfo> <arguments> <argument maturity="obsolete"> <name>name</name> <type> <string/> </type> <default>None</default> <description> The name of the authentication cache, this will be used to identify this authentication cache when the obsolete AuthPolicy construct is used. Setting this value is not required if AuthenticationPolicy is used. </description> </argument> <argument> <name>timeout</name> <type> <integer/> </type> <default>600</default> <description> Timeout while an authentication is assumed to be valid. </description> </argument> <argument> <name>update_stamp</name> <type> <boolean/> </type> <default>TRUE</default> <description> If set to <parameter>TRUE</parameter>, then cached authentications increase the validity period of the authentication cache. Otherwise, the authentication cache expires according to the timeout value set in <xref linkend="Auth___init___timeout"/><!-- FIXME ambiguous link, should point to previous attribute-->. </description> </argument> <argument> <name>service_equiv</name> <type> <boolean/> </type> <default>FALSE</default> <description>If enabled, then a single authentication of a user applies to every service from that client.</description> </argument> <argument> <name>cleanup_threshold</name> <type> <integer/> </type> <default>100</default> <description> When the number of entries in the cache reaches the value of <parameter>cleanup_threshold</parameter>, old entries are automatically deleted. </description> </argument> </arguments> </metainfo> </method> """ if name: self.name = name cache_name = 'authcache(%s)' % self.name else: cache_name = 'authcache(noname)' self.cache = LockedCache( TimedCache(cache_name, timeout, update_stamp, cleanup_threshold)) self.service_equiv = service_equiv if name: if Globals.auth_caches.has_key(name): raise ValueError, "Duplicate AuthCache name: %s" % name Globals.auth_caches[name] = self
class StateBasedChainer(MultiTargetChainer): """<class maturity="stable" abstract="yes"> <summary> Class encapsulating connection establishment with multiple target addresses and keeping down state between connects. </summary> <description> <para> This class encapsulates a real TCP/IP connection establishment, and is used when a top-level proxy wants to perform chaining. In addition to ConnectChainer, this class adds the capability to perform stateful, load balance server connections among a set of IP addresses. </para> <note> <para>Both the <link linkend="python.Chainer.FailoverChainer">FailoverChainer</link> and <link linkend="python.Chainer.RoundRobinChainer">RoundRobinChainer</link> classes are derived from StateBasedChainer.</para> </note> </description> <metainfo> <attributes> <attribute internal="yes"> <name>state</name> <type></type> <description>Down state of target hosts. </description> </attribute> </attributes> </metainfo> </class> """ def __init__(self, protocol=ZD_PROTO_AUTO, timeout_connect=None, timeout_state=None): """<method maturity="stable"> <summary> Constructor to initialize a StateBasedChainer instance. </summary> <description> <para> This constructor initializes a StateBasedChainer class by filling arguments with appropriate values and calling the inherited constructor. </para> </description> <metainfo> <arguments> <argument maturity="stable"> <name>protocol</name> <type> <link id="zorp.proto.id"/> </type> <default>ZD_PROTO_AUTO</default> <description> Optional, specifies connection protocol (<parameter> ZD_PROTO_TCP</parameter> or <parameter>ZD_PROTO_UDP </parameter>), when not specified it defaults to the same protocol used on the client side. </description> </argument> <argument> <name>timeout_connect</name> <type> <integer/> </type> <default>30000</default> <description> Specifies connection timeout to be used when connecting to the target server. </description> </argument> <argument> <name>timeout_state</name> <type> <integer/> </type> <default>60000</default> <description> The down state of remote hosts is kept for this interval in miliseconds. </description> </argument> </arguments> </metainfo> </method> """ MultiTargetChainer.__init__(self, protocol, timeout_connect) if not timeout_state: timeout_state = 60000 self.state = TimedCache('chainer-state', int((timeout_state + 999) / 1000), update_stamp=FALSE) def getNextTarget(self, session): """<method internal="yes"> </method> """ while 1: (target_local, target_remote) = MultiTargetChainer.getNextTarget(self, session) if not target_remote: # we enumerated all targets try: session.chainer_targets_enumerated = session.chainer_targets_enumerated + 1 except AttributeError: session.chainer_targets_enumerated = 1 if not self.state or session.chainer_targets_enumerated == 2: # we enumerated all our targets twice, once # with state held, and then all state # cleared, we were not successful, terminate # target iteration log(None, CORE_MESSAGE, 4, "All destinations are down for two full iterations, giving up;") return (None, None) ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log(None, CORE_MESSAGE, 4, "All destinations are down, clearing cache and trying again;") # we enumerated all targets, and all of them were # down, clear our state and try once more self.state.clear() self.restart(session) continue is_host_down = self.state.lookup(target_remote.ip_s) if not is_host_down: return (target_local, target_remote) else: ## LOG ## # This message reports that the remote end is down, but Zorp does not store the # down state of the remote end, so Zorp will try to connect to it next time. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, skipping; remote='%s'", (target_remote,)) def disableTarget(self, session, target_local, target_remote): """<method internal="yes"> </method> """ ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, keeping state; remote='%s'", (target_remote,)) self.state.store(target_remote.ip_s, 1)