I’ve recently been involved with configuring a client’s Citrix NetScalers to load balance inbound SMTP connections to Exchange and thought I’d take this opportunity to blog the process.
#1 – Configure Exchange Server Objects
Begin by creating the Exchange Server objects in Traffic Management > Load Balancing > Servers:
#2 – Create SMTP Monitor
Create an SMTP monitor object by navigating to Traffic Management > Load Balancing > Monitors:
Name: EXCH_MONITOR_SMTP
Type: SMTP
Interval: 5 second
Response Time-out: 2 second
Destination Port: Bound Service
Down Time: 30 second
Click on the Special Parameters tab and configure the following:
Script Name: nssmtp.pl
Dispatcher IP: 127.0.0.1
Dispatcher Port: 3013
Note that the nssmtp.pl script bundled with the NetScaler will go as far as attempting to open a connection to confirm that the service is up. The script and the actual code can be found in the following directory of the NetScaler:
/netscaler/monitors
#!/usr/bin/perl -w
################################################################
##
## Copyright 1998-2016 Citrix Systems, Inc. All rights reserved.
## This software and documentation contain valuable trade
## secrets and proprietary property belonging to Citrix Systems, Inc.
## None of this software and documentation may be copied,
## duplicated or disclosed without the express
## written permission of Citrix Systems, Inc.
##
################################################################
## This is a netscaler supplied script. Please dont modify this as it will be overwritten during
## reboot. If you want to modify, please make a copy of this script and modify.
## This script is used to do smtp monitoring using KAS feature.
use strict;
use Net::SMTP;
use Net::SMTP6;
use Netscaler::KAS;
sub is_ipv4_address
{
my $address = $_[0];
if ($address =~ m/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/) {
return 1;
}
return 0;
}
## This function is a handler for performing smtp probe in KAS mode
sub smtp_probe
{
## There must be at least 4 arguments to this function.
## 1. First argument is the IP that has to be probed.
## 2. Second argument is the port to connect to.
## 3. Timeout, it is present in index 3
if(scalar(@_) < 2)
{
return (1,”Invalid number of arguments”);
}
## Try to connect to the server
my $smtp;
if (is_ipv4_address($_[0])) {
$smtp=Net::SMTP->new($_[0].”:”.$_[1],Timeout=>$_[3])
or return (1,”Unable to connect to server – $!”);
## Probe succeeded
$smtp->quit;
return 0;
}
else { #IPV6 adress
$smtp=Net::SMTP6->new($_[0], PeerPort => $_[1], Timeout=>$_[3])
or return (1,”Unable to connect to server – $!”);
## Probe succeeded
$smtp->quit;
return 0;
}
}
## Register smtp probe handler, to the KAS module.
probe(&smtp_probe);
#3 – Configure Service Group
Proceed to configure the Service Group object by navigating to Traffic Management > Load Balancing > Service Groups:
Name: Exchange_2016_SMTP
Protocol: TCP
Cache Type: SERVER
Click on the No Service Group Member to add the Exchange server objects that were created in Step #1:
Click on the Monitors option on the right to add the SMTP monitor created in Step #2:
Complete the creation of the Service Group and you should now see the group listed with the State and Effective State as being up:
Step #4 – Create the Load Balancing Virtual Server
Continue to configure the load balancing virtual server object by navigating to Traffic Management > Load Balancing > Virtual Servers:
Add the Service Group created in Step #3:
Complete the creation of the load balancing virtual server and you should see State and Effective State listed as being up:
Step #5 – Lockdown Open Relay for Exchange Receive Connector
One of the common mistakes often overlooked when configuring SMTP load balancing via the NetScaler is inadvertently allowing open relay on the Exchange Server’s receive connector traffic coming from the NetScaler would appear to be an internal IP to the Exchange server. One of the ways to test whether the receive connector allows for open relay is to execute the following commands via telnet:
telnet exchangeServerFQDN 25
220 EXMB02.contoso.com Microsoft ESMTP MAIL Service ready at Thu, 1
2 Jan 2017 14:20:03 -0400
ehlo bogus.com
250-EXMB02.contoso.com Hello [10.21.1.32]
250-SIZE 37748736
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-8BITMIME
250-BINARYMIME
250 CHUNKING
mail from:bogus@bogus.com
250 2.1.0 Sender OK
rcpt to:validperson@domain.com
250 2.1.5 Recipient OK
Note that the mail from email address has a domain that is not hosted on the Exchange server and the rcpt to address is meant to be an email address that is also not hosted on the Exchange server. If the response to these commands is Recipient OK then your receive connect is allowing open relay. To correct this, ensure that the receiving connector has the Externally secured (for example, with IPsec) setting disabled:
Once the connect has been locked down, the following response is what the telnet commands would yield:
220 EXMB01.contoso.com Microsoft ESMTP MAIL Service ready at Thu, 1
2 Jan 2017 14:15:47 -0400
ehlo bogus.com
250-EXMB01.contoso.com Hello [10.21.1.32]
250-SIZE 37748736
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-8BITMIME
250-BINARYMIME
250 CHUNKING
mail from:bogus@bogus.com
250 2.1.0 Sender OK
rcpt to:validperson@google.com
550 5.7.54 SMTP; Unable to relay recipient in non-accepted domain
Step #6 – Lockdown SMTP Load Balancing Virtual Server Connectivity
Another often overlooked issue that load balancing SMTP requests through a NetScaler creates is that the Exchange server’s receive connectors no longer see the true source IP address because all of the requests now originate form the NetScaler’s NSIP address which means a malicious or unauthenticated internal device could potentially relay mail off of the load balancing virtual server and be able to successfully have the Exchange server deliver the email. This could be addressed by either configuring the Direct Server Return (DSR) feature on the NetScaler or simply locking down which IP addresses can connect to the load balancing virtual server. I won’t cover the configuration of DSR and will point to one of my previous blog posts to demonstrate how to lock down the load balancing virtual server: