#!/usr/bin/env ruby require 'ostruct' VERBOSE = true def die(msg = nil) puts msg if msg exit 1 end # Parse netstat output # Select only routes that are 'up' (flagged U) routes = [] begin res = %x{netstat -rn} res = res.split(/\n/).reject {|n| n =~ /^Kernel/ } names = res.shift.split(/\s+/).map {|name| name.downcase.to_sym } routes = res.map {|row| OpenStruct.new(Hash[*names.zip(row.split(/\s+/)).flatten]) }.select {|route| route.flags =~ /U/ } end # Find default gateway (flagged G) default = routes.select {|route| route.destination == '0.0.0.0' and route.genmask == '0.0.0.0' and route.flags =~ /G/ }.first # Sometimes the VPN will set a default route that's stupid, but works for point-to-point links if default.nil? default = routes.select {|route| route.destination == '0.0.0.0' and route.genmask == '0.0.0.0' and route.gateway == '0.0.0.0' }.first end # Find the gateway used by the VPN (flagged G and H). # Ignore any host routes on the same iface as the default gateway, as they may be added by the VPN itself. vpn = routes.select {|route| route.flags =~ /G/ and route.flags =~ /H/ and route.iface != default.iface } # Should have exactly one hostroute here. die "Couldn't guess route! Set manually." if vpn.length == 0 die "More than one possible route! Set manually." if vpn.length > 1 vpn = vpn.first # Nuke the existing default route printf("%s (%s)", default.gateway, default.iface) printf(" -> %s (%s)\n", vpn.gateway, vpn.iface) puts %w{/sbin/route delete -net default}.join(" ") if VERBOSE system(*%w{/sbin/route delete -net default}) || die("Route delete failed") puts %w{/sbin/route add -net default gw}.push(vpn.gateway).push('dev').push(vpn.iface).join(" ") if VERBOSE system(*%w{/sbin/route add -net default gw}.push(vpn.gateway).push('dev').push(vpn.iface)) || die("Route add failed")