1

I have a network with multiple gateways and one is set as the default gateway on a server. I want a single specific command to use a separate gateway for all its traffic. How would I achieve that?

Unfortunately using a destination IP route is not possible since I do not know the IPs that the command will contact beforehand.

What I really want to do is send all traffic through my default gateway and use a separate one for a script that uploads some stuff to Amazon S3. I achived it by getting Amazon's IPs from https://ip-ranges.amazonaws.com/ip-ranges.json and periodically updating the route table with the gateway I want for them but that feels hacky as hell.

I realise that there's no way to route traffic by domain name so could I do it some other way? Maybe with iptables or something similar?

Here's the script I whipped up for reference:

#!/usr/bin/env bash

set -eo pipefail
IFS=$'\n\t'

amazon_gateway='XXX.XXX.XXX.XXX'
amazon_ips_url='https://ip-ranges.amazonaws.com/ip-ranges.json'

route="$(which route)"
curl="$(which curl)"
jq="$(which jq)"
awk="$(which awk)"
netstat="$(which netstat)"

# taken from https://forums.gentoo.org/viewtopic-t-888736-start-0.html
mask2cdr ()
{
  # Assumes there's no "255." after a non-255 byte in the mask
  set -- 0^^^128^192^224^240^248^252^254^ ${#1} ${1##*255.}
  set -- $(( ($2 - ${#3})*2 )) ${1%%${3%%.*}*}
  echo $(( $1 + (${#2}/4) ))
}

# get amazon ips
amazon_ips=$("${curl}" "${amazon_ips_url}" | "${jq}" -r '.prefixes | map(select(.service == "AMAZON"))[].ip_prefix')

# get networks routed to requested gateway
routed_networks=$("${netstat}" -nr | "${awk}" '{ if ($2 == "'"${amazon_gateway}"'") print $1"/"$3 }')
# convert masks to cdrs
routed_networks=$(for network in ${routed_networks}; do echo "${network%\/*}/$(mask2cdr ${network#*\/})"; done)
# remove routes for all these networks
for network in ${routed_networks}; do "${route}" del -net "${network}" gw "${amazon_gateway}"; done
# add a route for each amazon ip
for amazon_ip in ${amazon_ips}; do "${route}" add -net "${amazon_ip}" gw "${amazon_gateway}"; done
eirc
  • 111
  • 3
  • You could configure iptables "mangle" capability and some policy routes so that traffic from any process owned by a certain uid uses a different gateway... – Michael - sqlbot Jul 22 '15 at 22:35
  • That's very close to what I want to do, that is mangling the packets will probably do it, however the other part of detecting based on uid is not the way I want to go since I want to run other (and unaffected by this) things with the same user. Looking into the IPTables manual I found that you can do this based on the process ID too. So maybe I'll try to make something you put *in* the mentioned upload script which would add the necessary mangle rules to IPTables for it's own PID. – eirc Jul 28 '15 at 12:48
  • @eirc Were you able to find a solution for this? – Behrooz Nov 23 '22 at 22:31
  • @Behrooz I don't think we ever did, we just used one gateway in the end. At least that's how we remember it 7 years later :) – eirc Nov 25 '22 at 10:22

0 Answers0