dialFunc returns a dial function. When proxyAddr is non-empty it routes all outbound connections through the SOCKS5 proxy at that address; otherwise it falls back to net.DialTimeout.
(proxyAddr string)
| 250 | // outbound connections through the SOCKS5 proxy at that address; otherwise it |
| 251 | // falls back to net.DialTimeout. |
| 252 | func dialFunc(proxyAddr string) func(network, address string, timeout time.Duration) (net.Conn, error) { |
| 253 | if proxyAddr == "" { |
| 254 | return net.DialTimeout |
| 255 | } |
| 256 | forward := &net.Dialer{Timeout: 15 * time.Second} |
| 257 | d, err := proxy.SOCKS5("tcp", proxyAddr, nil, forward) |
| 258 | if err != nil { |
| 259 | // proxy.SOCKS5 only errors on bad auth config; with nil auth this never fires. |
| 260 | log.Printf("[exit] upstream_proxy: failed to build SOCKS5 dialer: %v — falling back to direct", err) |
| 261 | return net.DialTimeout |
| 262 | } |
| 263 | cd, ok := d.(proxy.ContextDialer) |
| 264 | if !ok { |
| 265 | return func(_, address string, _ time.Duration) (net.Conn, error) { |
| 266 | return d.Dial("tcp", address) |
| 267 | } |
| 268 | } |
| 269 | return func(_, address string, timeout time.Duration) (net.Conn, error) { |
| 270 | ctx, cancel := context.WithTimeout(context.Background(), timeout) |
| 271 | defer cancel() |
| 272 | return cd.DialContext(ctx, "tcp", address) |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | // ListenAndServe blocks. It binds an HTTP listener on cfg.ListenAddr with one |
| 277 | // route, POST /tunnel, that handles batched encrypted frames. |