blob: d2e9f925b79b96e20d10e9b568a01cfef76a4cf8 [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
4# to make SOCKS5 or HTTPS proxy connections. It uses ALL_PROXY to determine the
5# proxy server, protocol, and port. It uses NO_PROXY to skip using the proxy for
6# a comma delimited list of hosts, host globs (*.example.com), IPs, or CIDR
7# masks (192.168.1.0/24). It is known to work with both bash and dash shells.
8#
9# Example ALL_PROXY values:
10# ALL_PROXY=socks://socks.example.com:1080
11# ALL_PROXY=https://proxy.example.com:8080
12#
13# Copyright (c) 2013, Intel Corporation.
14# All rights reserved.
15#
16# AUTHORS
17# Darren Hart <dvhart@linux.intel.com>
18
19# Locate the netcat binary
20SOCAT=$(which socat 2>/dev/null)
21if [ $? -ne 0 ]; then
22 echo "ERROR: socat binary not in PATH" 1>&2
23 exit 1
24fi
25METHOD=""
26
27# Test for a valid IPV4 quad with optional bitmask
28valid_ipv4() {
29 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]))?$"
30 return $?
31}
32
33# Convert an IPV4 address into a 32bit integer
34ipv4_val() {
35 IP="$1"
36 SHIFT=24
37 VAL=0
38 for B in ${IP//./ }; do
39 VAL=$(($VAL+$(($B<<$SHIFT))))
40 SHIFT=$(($SHIFT-8))
41 done
42 echo "$VAL"
43}
44
45# Determine if two IPs are equivalent, or if the CIDR contains the IP
46match_ipv4() {
47 CIDR=$1
48 IP=$2
49
50 if [ -z "${IP%%$CIDR}" ]; then
51 return 0
52 fi
53
54 # Determine the mask bitlength
55 BITS=${CIDR##*/}
Patrick Williamsf1e5d692016-03-30 15:21:19 -050056 [ "$BITS" != "$CIDR" ] || BITS=32
Patrick Williamsc124f4f2015-09-15 14:41:29 -050057 if [ -z "$BITS" ]; then
58 return 1
59 fi
60
61 IPVAL=$(ipv4_val $IP)
62 IP2VAL=$(ipv4_val ${CIDR%%/*})
63
64 # OR in the unmasked bits
65 for i in $(seq 0 $((32-$BITS))); do
66 IP2VAL=$(($IP2VAL|$((1<<$i))))
67 IPVAL=$(($IPVAL|$((1<<$i))))
68 done
69
70 if [ $IPVAL -eq $IP2VAL ]; then
71 return 0
72 fi
73 return 1
74}
75
76# Test to see if GLOB matches HOST
77match_host() {
78 HOST=$1
79 GLOB=$2
80
81 if [ -z "${HOST%%$GLOB}" ]; then
82 return 0
83 fi
84
85 # Match by netmask
86 if valid_ipv4 $GLOB; then
87 HOST_IP=$(gethostip -d $HOST)
88 if valid_ipv4 $HOST_IP; then
89 match_ipv4 $GLOB $HOST_IP
90 if [ $? -eq 0 ]; then
91 return 0
92 fi
93 fi
94 fi
95
96 return 1
97}
98
99# If no proxy is set or needed, just connect directly
100METHOD="TCP:$1:$2"
101
102if [ -z "$ALL_PROXY" ]; then
103 exec $SOCAT STDIO $METHOD
104fi
105
106# Connect directly to hosts in NO_PROXY
107for H in ${NO_PROXY//,/ }; do
108 if match_host $1 $H; then
109 exec $SOCAT STDIO $METHOD
110 fi
111done
112
113# Proxy is necessary, determine protocol, server, and port
114PROTO=$(echo $ALL_PROXY | sed -e 's/\([^:]*\):\/\/.*/\1/')
115PROXY=$(echo $ALL_PROXY | sed -e 's/.*:\/\/\([^:]*\).*/\1/')
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500116# For backwards compatibility, this allows the port number to be followed by /?
117# in addition to the customary optional /
118PORT=$(echo $ALL_PROXY | sed -e 's/.*:\([0-9]*\)\(\/?\?\)\?$/\1/')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119if [ "$PORT" = "$ALL_PROXY" ]; then
120 PORT=""
121fi
122
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500123if [ "$PROTO" = "socks" ] || [ "$PROTO" = "socks4a" ]; then
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124 if [ -z "$PORT" ]; then
125 PORT="1080"
126 fi
127 METHOD="SOCKS4A:$PROXY:$1:$2,socksport=$PORT"
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500128elif [ "$PROTO" = "socks4" ]; then
129 if [ -z "$PORT" ]; then
130 PORT="1080"
131 fi
132 METHOD="SOCKS4:$PROXY:$1:$2,socksport=$PORT"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500133else
134 # Assume PROXY (http, https, etc)
135 if [ -z "$PORT" ]; then
136 PORT="8080"
137 fi
138 METHOD="PROXY:$PROXY:$1:$2,proxyport=$PORT"
139fi
140
141exec $SOCAT STDIO $METHOD