/
lookupproxy.go
168 lines (155 loc) · 5.19 KB
/
lookupproxy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright (c) 2018 Zededa, Inc.
// SPDX-License-Identifier: Apache-2.0
package zedcloud
import (
"encoding/base64"
"errors"
"fmt"
"net/url"
"strings"
"github.com/lf-edge/eve-libs/zedUpload"
"github.com/lf-edge/eve/pkg/pillar/base"
"github.com/lf-edge/eve/pkg/pillar/types"
"github.com/lf-edge/eve/pkg/pillar/zedpac"
)
func LookupProxy(log *base.LogObject, status *types.DeviceNetworkStatus, ifname string,
rawUrl string) (*url.URL, error) {
for _, port := range status.Ports {
log.Tracef("LookupProxy: Looking for proxy config on port %s",
port.IfName)
if port.IfName != ifname {
continue
}
log.Tracef("LookupProxy: Port configuration found for %s", ifname)
proxyConfig := port.ProxyConfig
// Check if the URL is present in exception list
// XXX Should we just get the domain name part of URL and compare?
// XXX Doing the domain portion comparison for now.
// Parse url and find the host domain part
u, err := url.Parse(rawUrl)
if err != nil {
errStr := fmt.Sprintf("LookupProxy: malformed URL %s", rawUrl)
log.Errorf(errStr)
return nil, errors.New(errStr)
}
// Check if we have a PAC file
if len(proxyConfig.Pacfile) > 0 {
pacFile, err := base64.StdEncoding.DecodeString(proxyConfig.Pacfile)
if err != nil {
errStr := fmt.Sprintf("LookupProxy: Decoding proxy file failed: %s", err)
log.Errorf(errStr)
return nil, errors.New(errStr)
}
proxyString, err := zedpac.Find_proxy_sync(
string(pacFile), rawUrl, u.Host)
if err != nil {
errStr := fmt.Sprintf("LookupProxy: PAC file could not find proxy for %s: %s",
rawUrl, err)
log.Errorf(errStr)
return nil, errors.New(errStr)
}
//if proxyString == "DIRECT" {
if strings.HasPrefix(proxyString, "DIRECT") {
return nil, nil
}
proxies := strings.Split(proxyString, ";")
if len(proxies) == 0 {
log.Errorf("LookupProxy: Number of proxies in PAC file result is Zero")
return nil, nil
}
// XXX Take the first proxy for now. Failing over to the next
// proxy should be implemented
proxy0 := proxies[0]
proxy0 = strings.Split(proxy0, " ")[1]
// Proxy address returned by PAC does not have the URL scheme.
// We prepend the scheme (http/https) of the incoming raw URL.
proxy0 = "http://" + proxy0
proxy, err := url.Parse(proxy0)
if err != nil {
errStr := fmt.Sprintf("LookupProxy: PAC file returned invalid proxy %s: %s",
proxyString, err)
log.Errorf(errStr)
return nil, errors.New(errStr)
}
log.Tracef("LookupProxy: PAC proxy being used is %s", proxy0)
return proxy, err
}
config := &Config{}
for _, proxy := range proxyConfig.Proxies {
switch proxy.Type {
case types.NetworkProxyTypeHTTP:
var httpProxy string
if proxy.Port > 0 {
httpProxy = fmt.Sprintf("%s:%d", proxy.Server, proxy.Port)
} else {
httpProxy = fmt.Sprintf("%s", proxy.Server)
}
config.HTTPProxy = httpProxy
log.Tracef("LookupProxy: Adding HTTP proxy %s for port %s",
config.HTTPProxy, ifname)
case types.NetworkProxyTypeHTTPS:
var httpsProxy string
if proxy.Port > 0 {
httpsProxy = fmt.Sprintf("%s:%d", proxy.Server, proxy.Port)
} else {
httpsProxy = fmt.Sprintf("%s", proxy.Server)
}
config.HTTPSProxy = httpsProxy
log.Tracef("LookupProxy: Adding HTTPS proxy %s for port %s",
config.HTTPSProxy, ifname)
default:
// XXX We should take care of Socks proxy, FTP proxy also in future
}
}
config.NoProxy = proxyConfig.Exceptions
proxyFunc := config.ProxyFunc()
proxy, err := proxyFunc(u)
if err != nil {
errStr := fmt.Sprintf("LookupProxy: proxyFunc error: %s", err)
log.Errorf(errStr)
return proxy, errors.New(errStr)
}
return proxy, err
}
log.Functionf("LookupProxy: No proxy configured for port %s", ifname)
return nil, nil
}
// IntfLookupProxyCfg - check if the intf has proxy configured
func IntfLookupProxyCfg(log *base.LogObject, status *types.DeviceNetworkStatus, ifname, downloadURL string,
trType zedUpload.SyncTransportType) string {
// if proxy is not on the intf, then don't change anything
// if download URL has "http://" or "https://" then no change here regardless of proxy
// if there is proxy on this intf, treat empty url scheme as for https or http but prefer https,
// replace the passed-in download-url scheme "docker://" and maybe "sftp://" later, to https
// XXX for sftp, currently the FQDN can not have scheme attached, but url.Parse will fail without it
if !strings.Contains(downloadURL, "://") {
switch trType {
case zedUpload.SyncSftpTr:
downloadURL = "http://" + downloadURL
case zedUpload.SyncOCIRegistryTr, zedUpload.SyncHttpTr:
downloadURL = "https://" + downloadURL
default:
downloadURL = "https://" + downloadURL
}
}
passURL, err := url.Parse(downloadURL)
if err != nil {
return downloadURL
}
switch passURL.Scheme {
case "http", "https":
return downloadURL
}
tmpURL := passURL
tmpURL.Scheme = "https"
proxyURL, err := LookupProxy(log, status, ifname, tmpURL.String())
if err == nil && proxyURL != nil {
return tmpURL.String()
}
tmpURL.Scheme = "http"
proxyURL, err = LookupProxy(log, status, ifname, tmpURL.String())
if err == nil && proxyURL != nil {
return tmpURL.String()
}
return downloadURL
}