blob: 1800942f3642ade8f997b00588e18df004fb5e6d [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/bin/bash
2
3# oe-git-proxy is a simple tool to be via GIT_PROXY_COMMAND. It uses socat
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05004# to make SOCKS5 or HTTPS proxy connections.
5# It uses ALL_PROXY or all_proxy or http_proxy to determine the proxy server,
6# protocol, and port.
7# It uses NO_PROXY to skip using the proxy for a comma delimited list of
8# hosts, host globs (*.example.com), IPs, or CIDR masks (192.168.1.0/24). It
9# is known to work with both bash and dash shells.
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
11# Example ALL_PROXY values:
12# ALL_PROXY=socks://socks.example.com:1080
13# ALL_PROXY=https://proxy.example.com:8080
14#
15# Copyright (c) 2013, Intel Corporation.
16# All rights reserved.
17#
18# AUTHORS
19# Darren Hart <dvhart@linux.intel.com>
20
Brad Bishop6e60e8b2018-02-01 10:27:11 -050021if [ $# -lt 2 -o "$1" = '--help' -o "$1" = '-h' ] ; then
22 echo 'oe-git-proxy: error: the following arguments are required: host port'
23 echo 'Usage: oe-git-proxy host port'
24 echo ''
25 echo 'OpenEmbedded git-proxy - a simple tool to be used via GIT_PROXY_COMMAND.'
26 echo 'It uses socat to make SOCKS or HTTPS proxy connections.'
27 echo 'It uses ALL_PROXY to determine the proxy server, protocol, and port.'
28 echo 'It uses NO_PROXY to skip using the proxy for a comma delimited list'
29 echo 'of hosts, host globs (*.example.com), IPs, or CIDR masks (192.168.1.0/24).'
30 echo 'It is known to work with both bash and dash shells.runs native tools'
31 echo ''
32 echo 'arguments:'
33 echo ' host proxy host to use'
34 echo ' port proxy port to use'
35 echo ''
36 echo 'options:'
37 echo ' -h, --help show this help message and exit'
38 echo ''
39 exit 2
40fi
41
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042# Locate the netcat binary
43SOCAT=$(which socat 2>/dev/null)
44if [ $? -ne 0 ]; then
45 echo "ERROR: socat binary not in PATH" 1>&2
46 exit 1
47fi
48METHOD=""
49
50# Test for a valid IPV4 quad with optional bitmask
51valid_ipv4() {
52 echo $1 | egrep -q "^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}(/(3[0-2]|[1-2]?[0-9]))?$"
53 return $?
54}
55
56# Convert an IPV4 address into a 32bit integer
57ipv4_val() {
58 IP="$1"
59 SHIFT=24
60 VAL=0
61 for B in ${IP//./ }; do
62 VAL=$(($VAL+$(($B<<$SHIFT))))
63 SHIFT=$(($SHIFT-8))
64 done
65 echo "$VAL"
66}
67
68# Determine if two IPs are equivalent, or if the CIDR contains the IP
69match_ipv4() {
70 CIDR=$1
71 IP=$2
72
73 if [ -z "${IP%%$CIDR}" ]; then
74 return 0
75 fi
76
77 # Determine the mask bitlength
78 BITS=${CIDR##*/}
Patrick Williamsf1e5d692016-03-30 15:21:19 -050079 [ "$BITS" != "$CIDR" ] || BITS=32
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080 if [ -z "$BITS" ]; then
81 return 1
82 fi
83
84 IPVAL=$(ipv4_val $IP)
85 IP2VAL=$(ipv4_val ${CIDR%%/*})
86
87 # OR in the unmasked bits
88 for i in $(seq 0 $((32-$BITS))); do
89 IP2VAL=$(($IP2VAL|$((1<<$i))))
90 IPVAL=$(($IPVAL|$((1<<$i))))
91 done
92
93 if [ $IPVAL -eq $IP2VAL ]; then
94 return 0
95 fi
96 return 1
97}
98
99# Test to see if GLOB matches HOST
100match_host() {
101 HOST=$1
102 GLOB=$2
103
104 if [ -z "${HOST%%$GLOB}" ]; then
105 return 0
106 fi
107
108 # Match by netmask
109 if valid_ipv4 $GLOB; then
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600110 for HOST_IP in $(getent ahostsv4 $HOST | grep ' STREAM ' | cut -d ' ' -f 1) ; do
111 if valid_ipv4 $HOST_IP; then
112 match_ipv4 $GLOB $HOST_IP
113 if [ $? -eq 0 ]; then
114 return 0
115 fi
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500116 fi
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600117 done
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500118 fi
119
120 return 1
121}
122
123# If no proxy is set or needed, just connect directly
124METHOD="TCP:$1:$2"
125
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500126[ -z "${ALL_PROXY}" ] && ALL_PROXY=$all_proxy
127[ -z "${ALL_PROXY}" ] && ALL_PROXY=$http_proxy
128
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129if [ -z "$ALL_PROXY" ]; then
130 exec $SOCAT STDIO $METHOD
131fi
132
133# Connect directly to hosts in NO_PROXY
Andrew Geissler99467da2019-02-25 18:54:23 -0600134for H in "${NO_PROXY//,/ }"; do
135 if match_host $1 "$H"; then
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136 exec $SOCAT STDIO $METHOD
137 fi
138done
139
140# Proxy is necessary, determine protocol, server, and port
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500141# extract protocol
142PROTO=${ALL_PROXY%://*}
143# strip protocol:// from string
144ALL_PROXY=${ALL_PROXY#*://}
145# extract host & port parts:
146# 1) drop username/password
147PROXY=${ALL_PROXY##*@}
148# 2) remove optional trailing /?
149PROXY=${PROXY%%/*}
150# 3) extract optional port
151PORT=${PROXY##*:}
152if [ "$PORT" = "$PROXY" ]; then
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153 PORT=""
154fi
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500155# 4) remove port
156PROXY=${PROXY%%:*}
157
158# extract username & password
159PROXYAUTH="${ALL_PROXY%@*}"
160[ "$PROXYAUTH" = "$ALL_PROXY" ] && PROXYAUTH=
161[ -n "${PROXYAUTH}" ] && PROXYAUTH=",proxyauth=${PROXYAUTH}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500163if [ "$PROTO" = "socks" ] || [ "$PROTO" = "socks4a" ]; then
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164 if [ -z "$PORT" ]; then
165 PORT="1080"
166 fi
167 METHOD="SOCKS4A:$PROXY:$1:$2,socksport=$PORT"
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500168elif [ "$PROTO" = "socks4" ]; then
169 if [ -z "$PORT" ]; then
170 PORT="1080"
171 fi
172 METHOD="SOCKS4:$PROXY:$1:$2,socksport=$PORT"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173else
174 # Assume PROXY (http, https, etc)
175 if [ -z "$PORT" ]; then
176 PORT="8080"
177 fi
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500178 METHOD="PROXY:$PROXY:$1:$2,proxyport=${PORT}${PROXYAUTH}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179fi
180
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500181exec $SOCAT STDIO "$METHOD"