mirror of
https://github.com/sshuttle/sshuttle.git
synced 2024-11-25 01:13:37 +01:00
refactor for future ipv6 support
This commit is contained in:
parent
dadfba488b
commit
1885974f52
@ -8,7 +8,10 @@ services:
|
|||||||
cap_add:
|
cap_add:
|
||||||
- "NET_ADMIN"
|
- "NET_ADMIN"
|
||||||
environment:
|
environment:
|
||||||
- IP_ADDRESSES=10.55.1.77/24
|
- ADD_IP_ADDRESSES=10.55.1.77/24
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
ipv6_address: 2001:0DB8::551
|
||||||
node-2:
|
node-2:
|
||||||
image: ghcr.io/sshuttle/sshuttle-testbed
|
image: ghcr.io/sshuttle/sshuttle-testbed
|
||||||
container_name: sshuttle-testbed-node-2
|
container_name: sshuttle-testbed-node-2
|
||||||
@ -16,9 +19,16 @@ services:
|
|||||||
cap_add:
|
cap_add:
|
||||||
- "NET_ADMIN"
|
- "NET_ADMIN"
|
||||||
environment:
|
environment:
|
||||||
- IP_ADDRESSES=10.55.2.77/32
|
- ADD_IP_ADDRESSES=10.55.2.77/32
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
ipv6_address: 2001:0DB8::552
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
default:
|
default:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
enable_ipv6: true
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 2001:0DB8::/112
|
||||||
# internal: true
|
# internal: true
|
@ -11,7 +11,6 @@ function with_set_x() {
|
|||||||
} 2>/dev/null
|
} 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssh_cmd='ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
ssh_cmd='ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||||
args=()
|
args=()
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@ -25,12 +24,15 @@ while [[ $# -gt 0 ]]; do
|
|||||||
ssh_copy_id=true
|
ssh_copy_id=true
|
||||||
continue
|
continue
|
||||||
;;
|
;;
|
||||||
|
-6)
|
||||||
|
ipv6_only=true
|
||||||
|
continue
|
||||||
|
;;
|
||||||
--sshuttle-bin=*)
|
--sshuttle-bin=*)
|
||||||
sshuttle_bin="${arg#*=}"
|
sshuttle_bin="${arg#*=}"
|
||||||
continue
|
continue
|
||||||
;;
|
;;
|
||||||
-*)
|
-*) ;;
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
if [[ -z "$node" ]]; then
|
if [[ -z "$node" ]]; then
|
||||||
node=$arg
|
node=$arg
|
||||||
@ -41,14 +43,17 @@ while [[ $# -gt 0 ]]; do
|
|||||||
args+=("$arg")
|
args+=("$arg")
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
port="2222"
|
port="2222"
|
||||||
user="test:test"
|
user="test:test"
|
||||||
|
|
||||||
if [[ $node == node-* ]]; then
|
if [[ $node == node-* ]]; then
|
||||||
host=$("$(dirname "$0")/test-bed" get-ip "$node")
|
host=$("$(dirname "$0")/test-bed" get-ip "$node")
|
||||||
index=${node#node-}
|
index=${node#node-}
|
||||||
|
if [[ $ipv6_only == true ]]; then
|
||||||
|
args+=("2001:0DB8::/112")
|
||||||
|
else
|
||||||
args+=("10.55.$index.0/24")
|
args+=("10.55.$index.0/24")
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
host=$node
|
host=$node
|
||||||
fi
|
fi
|
||||||
@ -77,4 +82,3 @@ fi
|
|||||||
set -x
|
set -x
|
||||||
|
|
||||||
exec "${sshuttle_bin}" -r "$user@$host:$port" --ssh-cmd "$ssh_cmd" "${args[@]}"
|
exec "${sshuttle_bin}" -r "$user@$host:$port" --ssh-cmd "$ssh_cmd" "${args[@]}"
|
||||||
|
|
||||||
|
@ -1,13 +1,39 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
tool=${1?:"tool argument missing. should be one of iperf3,ping,curl,ab"}
|
args=()
|
||||||
node=${2?:"node argument missing. should be 'node-1' , 'node-2' etc"}
|
while [[ $# -gt 0 ]]; do
|
||||||
shift 2
|
arg=$1
|
||||||
|
shift
|
||||||
|
case "$arg" in
|
||||||
|
-6)
|
||||||
|
ipv6_only=true
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
-*) ;;
|
||||||
|
*)
|
||||||
|
if [[ -z $tool ]]; then
|
||||||
|
tool=$arg
|
||||||
|
continue
|
||||||
|
elif [[ -z $node ]]; then
|
||||||
|
node=$arg
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
args+=("$arg")
|
||||||
|
done
|
||||||
|
|
||||||
|
tool=${tool?:"tool argument missing. should be one of iperf3,ping,curl,ab"}
|
||||||
|
node=${node?:"node argument missing. should be 'node-1' , 'node-2' etc"}
|
||||||
|
|
||||||
if [[ $node == node-* ]]; then
|
if [[ $node == node-* ]]; then
|
||||||
index=${node#node-}
|
index=${node#node-}
|
||||||
|
if [[ $ipv6_only == true ]]; then
|
||||||
|
host="2001:0DB8::55$index"
|
||||||
|
else
|
||||||
host="10.55.$index.77"
|
host="10.55.$index.77"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
host=$node
|
host=$node
|
||||||
fi
|
fi
|
||||||
@ -26,22 +52,26 @@ function with_set_x() {
|
|||||||
|
|
||||||
case "$tool" in
|
case "$tool" in
|
||||||
ping)
|
ping)
|
||||||
with_set_x exec ping -W $connect_timeout_sec "$@" "$host"
|
with_set_x exec ping -W $connect_timeout_sec "${args[@]}" "$host"
|
||||||
;;
|
;;
|
||||||
iperf3)
|
iperf3)
|
||||||
port=5001
|
port=5001
|
||||||
with_set_x exec iperf3 --client "$host" --port=$port --connect-timeout=$((connect_timeout_sec * 1000)) "$@"
|
with_set_x exec iperf3 --client "$host" --port=$port --connect-timeout=$((connect_timeout_sec * 1000)) "${args[@]}"
|
||||||
;;
|
;;
|
||||||
curl)
|
curl)
|
||||||
port=8080
|
port=8080
|
||||||
with_set_x exec curl "http://$host:$port/" -v --connect-timeout $connect_timeout_sec "$@"
|
if [[ $host = *:* ]]; then
|
||||||
|
host="[$host]"
|
||||||
|
args+=(--ipv6)
|
||||||
|
fi
|
||||||
|
with_set_x exec curl "http://$host:$port/" -v --connect-timeout $connect_timeout_sec "${args[@]}"
|
||||||
;;
|
;;
|
||||||
ab)
|
ab)
|
||||||
port=8080
|
port=8080
|
||||||
if [[ " $*" != *" -n "* && " $*" != *" -c "* ]]; then
|
if [[ " ${args[*]}" != *" -n "* && " ${args[*]}" != *" -c "* ]]; then
|
||||||
set -- -n 500 -c 50 "$@"
|
args+=(-n 500 -c 50 "${args[@]}")
|
||||||
fi
|
fi
|
||||||
with_set_x exec ab -s $connect_timeout_sec "$@" "http://$host:$port/"
|
with_set_x exec ab -s $connect_timeout_sec "${args[@]}" "http://$host:$port/"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown tool: $tool" >&2
|
echo "Unknown tool: $tool" >&2
|
||||||
|
@ -17,7 +17,7 @@ function with_set_x() {
|
|||||||
|
|
||||||
iface="$(ip route | awk '/default/ { print $5 }')"
|
iface="$(ip route | awk '/default/ { print $5 }')"
|
||||||
default_gw="$(ip route | awk '/default/ { print $3 }')"
|
default_gw="$(ip route | awk '/default/ { print $3 }')"
|
||||||
for addr in ${IP_ADDRESSES//,/ }; do
|
for addr in ${ADD_IP_ADDRESSES//,/ }; do
|
||||||
echo ">>> Adding $addr to interface $iface"
|
echo ">>> Adding $addr to interface $iface"
|
||||||
net_addr=$(ipcalc -n "$addr" | awk -F= '{print $2}')
|
net_addr=$(ipcalc -n "$addr" | awk -F= '{print $2}')
|
||||||
with_set_x ip addr add "$addr" dev "$iface"
|
with_set_x ip addr add "$addr" dev "$iface"
|
||||||
|
@ -255,8 +255,8 @@ class ConnTrack:
|
|||||||
state_epoch,
|
state_epoch,
|
||||||
state,
|
state,
|
||||||
) = self.struct_full_tuple.unpack(packed)
|
) = self.struct_full_tuple.unpack(packed)
|
||||||
dst_addr = str(ip_address(dst_addr_packed if ip_version == 6 else dst_addr_packed[:4]))
|
dst_addr = ip_address(dst_addr_packed if ip_version == 6 else dst_addr_packed[:4]).exploded
|
||||||
src_addr = str(ip_address(src_addr_packed if ip_version == 6 else src_addr_packed[:4]))
|
src_addr = ip_address(src_addr_packed if ip_version == 6 else src_addr_packed[:4]).exploded
|
||||||
return ConnectionTuple(
|
return ConnectionTuple(
|
||||||
IPProtocol(proto), ip_version, src_addr, src_port, dst_addr, dst_port, state_epoch, ConnState(state)
|
IPProtocol(proto), ip_version, src_addr, src_port, dst_addr, dst_port, state_epoch, ConnState(state)
|
||||||
)
|
)
|
||||||
@ -306,14 +306,15 @@ class Method(BaseMethod):
|
|||||||
# As a workaround, finding another interface ip instead. (client should not bind proxy to loopback address)
|
# As a workaround, finding another interface ip instead. (client should not bind proxy to loopback address)
|
||||||
local_addr = self._get_bind_addresses_for_port(proxy_port, family)
|
local_addr = self._get_bind_addresses_for_port(proxy_port, family)
|
||||||
for addr in (ip_address(info[4][0]) for info in socket.getaddrinfo(socket.gethostname(), None)):
|
for addr in (ip_address(info[4][0]) for info in socket.getaddrinfo(socket.gethostname(), None)):
|
||||||
if addr.is_loopback or addr.version != family.version:
|
if addr.version != family.version or addr.is_loopback or addr.is_link_local:
|
||||||
continue
|
continue
|
||||||
if local_addr.is_unspecified or local_addr == addr:
|
if local_addr.is_unspecified or local_addr == addr:
|
||||||
debug2("Found non loopback address to connect to proxy: " + str(addr))
|
proxy_ip = addr.exploded
|
||||||
proxy_ip = str(addr)
|
debug2("Found non loopback address to connect to proxy: " + proxy_ip)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise Fatal("Windivert method requires proxy to listen on a non loopback address")
|
raise Fatal("Windivert method requires proxy to be reachable by a non loopback address."
|
||||||
|
f"No addersss found for {family.name}")
|
||||||
|
|
||||||
subnet_addresses = []
|
subnet_addresses = []
|
||||||
for (_, mask, exclude, network_addr, fport, lport) in subnets:
|
for (_, mask, exclude, network_addr, fport, lport) in subnets:
|
||||||
@ -388,15 +389,18 @@ class Method(BaseMethod):
|
|||||||
subnet_filters = []
|
subnet_filters = []
|
||||||
for cidr in c["subnets"]:
|
for cidr in c["subnets"]:
|
||||||
ip_net = ip_network(cidr)
|
ip_net = ip_network(cidr)
|
||||||
first_ip = ip_net.network_address
|
first_ip = ip_net.network_address.exploded
|
||||||
last_ip = ip_net.broadcast_address
|
last_ip = ip_net.broadcast_address.exploded
|
||||||
subnet_filters.append(f"({af.filter}.DstAddr>={first_ip} and {af.filter}.DstAddr<={last_ip})")
|
subnet_filters.append(f"({af.filter}.DstAddr>={first_ip} and {af.filter}.DstAddr<={last_ip})")
|
||||||
|
if not subnet_filters:
|
||||||
|
continue
|
||||||
proxy_ip, proxy_port = c["proxy_addr"]
|
proxy_ip, proxy_port = c["proxy_addr"]
|
||||||
proxy_guard_filter = f'({af.filter}.DstAddr!={proxy_ip} or tcp.DstPort!={proxy_port})'
|
proxy_guard_filter = f'({af.filter}.DstAddr!={proxy_ip} or tcp.DstPort!={proxy_port})'
|
||||||
family_filters.append(f"{af.filter} and ({' or '.join(subnet_filters)}) and {proxy_guard_filter}")
|
family_filters.append(f"{af.filter} and ({' or '.join(subnet_filters)}) and {proxy_guard_filter}")
|
||||||
|
if not family_filters:
|
||||||
|
raise Fatal("At least one ipv4 or ipv6 subnet is expected")
|
||||||
|
|
||||||
filter = f"{filter} and ({' or '.join(family_filters)})"
|
filter = f"{filter} and ({' or '.join(family_filters)})"
|
||||||
|
|
||||||
debug1(f"[EGRESS] {filter=}")
|
debug1(f"[EGRESS] {filter=}")
|
||||||
with pydivert.WinDivert(filter, layer=pydivert.Layer.NETWORK, flags=pydivert.Flag.DEFAULT) as w:
|
with pydivert.WinDivert(filter, layer=pydivert.Layer.NETWORK, flags=pydivert.Flag.DEFAULT) as w:
|
||||||
ready_cb()
|
ready_cb()
|
||||||
@ -444,6 +448,8 @@ class Method(BaseMethod):
|
|||||||
direction = "outbound"
|
direction = "outbound"
|
||||||
proxy_addr_filters = []
|
proxy_addr_filters = []
|
||||||
for af, c in self.network_config.items():
|
for af, c in self.network_config.items():
|
||||||
|
if not c["subnets"]:
|
||||||
|
continue
|
||||||
proxy_ip, proxy_port = c["proxy_addr"]
|
proxy_ip, proxy_port = c["proxy_addr"]
|
||||||
# "ip.SrcAddr=={hex(int(proxy_ip))}" # only Windivert >=2 supports this
|
# "ip.SrcAddr=={hex(int(proxy_ip))}" # only Windivert >=2 supports this
|
||||||
proxy_addr_filters.append(f"{af.filter}.SrcAddr=={proxy_ip} and tcp.SrcPort=={proxy_port}")
|
proxy_addr_filters.append(f"{af.filter}.SrcAddr=={proxy_ip} and tcp.SrcPort=={proxy_port}")
|
||||||
|
Loading…
Reference in New Issue
Block a user