Exemple #1
0
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)
Exemple #2
0
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>"&lt;&gt;"</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
Exemple #3
0
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>"&lt;&gt;"</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
Exemple #4
0
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)