in src/common/IP/IPManager.cs [148:236]
private void AddRoutingRules(IEnumerable<EndpointInfo> endpoints, CancellationToken cancellationToken)
{
if (_platform.IsWindows)
{
return;
}
using (var perfLogger =
_log.StartPerformanceLogger(
Events.IP.AreaName,
Events.IP.Operations.AddRoutingRules))
{
if (_platform.IsOSX)
{
// TODO: Fix Bug 1125798: Need to be a good pf citizen
StringBuilder inputBuilder = new StringBuilder();
foreach (var endpoint in endpoints)
{
if (endpoint.LocalIP.Equals(IPAddress.Loopback))
{
continue;
}
foreach (var portPair in endpoint.Ports)
{
inputBuilder.AppendLine($"rdr pass inet proto tcp from any to {endpoint.LocalIP} port {portPair.RemotePort} -> {endpoint.LocalIP} port {portPair.LocalPort}");
}
}
lock (_syncObject)
{
_log.Info("Updating routing table...");
(var exitCode, var output) = _platform.ExecuteAndReturnOutput(
command: "/sbin/pfctl",
arguments: "-ef -",
timeout: TimeSpan.FromSeconds(10),
stdOutCallback: (line) => _log.Verbose(line),
stdErrCallback: (line) => _log.Error(line),
processInput: inputBuilder.ToString());
var resultMessage = $"'/sbin/pfctl -ef - {inputBuilder}' returned exit code {exitCode}";
if (exitCode != 0)
{
_log.Warning(resultMessage);
}
else
{
_log.Info(resultMessage);
}
_log.Verbose($"All output: {output}");
perfLogger.SetSucceeded();
}
}
else if (_platform.IsLinux)
{
var rules = new List<string>();
foreach (var endpoint in endpoints)
{
foreach (var portPair in endpoint.Ports)
{
// --wait -w [seconds] maximum wait to acquire xtables lock before give up
rules.Add($"--table nat --append PREROUTING -p tcp --dst {endpoint.LocalIP} --dport {portPair.RemotePort} --jump DNAT --to-destination {endpoint.LocalIP}:{portPair.LocalPort} --wait 30");
rules.Add($"--table nat --append OUTPUT -p tcp --dst {endpoint.LocalIP} --dport {portPair.RemotePort} --jump DNAT --to-destination {endpoint.LocalIP}:{portPair.LocalPort} --wait 30");
}
}
lock (_syncObject)
{
_log.Info("Adding rules to routing table...");
foreach (var rule in rules)
{
if (_linuxRoutingRules.Add(rule))
{
(var exitCode, var output) = RunUtility("iptables", rule, cancellationToken); // Only apply the rule if it wasn't previously present in the ruleset
if (exitCode != 0)
{
throw new InvalidUsageException(_log.OperationContext, $"Running 'iptables' failed with exit code '{exitCode}': '{output}'");
}
}
}
perfLogger.SetSucceeded();
}
}
else
{
throw new NotSupportedException("Unsupported platform");
}
}
}