README

= h2s
Equim <https://github.com/Equim-chan[@Equim-chan]>

image:http://img.shields.io/badge/godoc-reference-5272B4.svg[GoDoc, link=https://godoc.org/ekyu.moe/h2s]
image:https://img.shields.io/github/release/Equim-chan/h2s.svg[Release, link=https://github.com/Equim-chan/h2s/releases/latest]
image:https://img.shields.io/circleci/project/github/Equim-chan/h2s.svg[CircleCI, link=https://circleci.com/gh/Equim-chan/h2s]
image:https://goreportcard.com/badge/github.com/Equim-chan/h2s[Go Report Card, link=https://goreportcard.com/report/github.com/Equim-chan/h2s]
image:https://img.shields.io/github/license/Equim-chan/h2s.svg[License, link=https://github.com/Equim-chan/h2s/blob/master/LICENSE]

h2s is a tiny CLI tool that wraps one or multiple HTTPS proxies into a SOCKS5 proxy. It does something like https://www.irif.fr/~jch/software/polipo/[polipo] and http://www.privoxy.org/[privoxy] do, but in a reversed way.

There are already some SOCKS to HTTPS tools out there, but I can hardly find a reversed one (HTTPS to SOCKS), so I decided to make one on my own.

== Install
You can view the https://github.com/Equim-chan/h2s/releases[release] page for handy prebuilt binaries.

== Build from Source
h2s relies on stadard libs only.

[source,bash]
----
$ go get -u ekyu.moe/h2s/cmd/h2s
----

== Configure
An example config file:

[source,js]
----
{
  // bind is the address h2s will listen to.
  // Note that since HTTPS proxy support only TCP, the h2s wrapped SOCKS5
  // proxy consequently support only TCP as well.
  "bind": "127.0.0.1:1080",

  // upstreams are HTTPS proxy upstreams.
  // h2s will do a simple round-robin load balance.
  "upstreams": [{
    // If no port is specified, 80 is assumed by default.
    "address": "proxy1.example.com",
  }, {
    "address": "proxy2.example.com:3128",

    // username and password are optional for proxy authentication.
    "username": "Alice",
    "password": "secret here"
  }, {
    // An HTTPS proxy over TLS upstream.
    // You have to specify port explicitly (usually 443), and set the tls field.
    "address": "secure.proxy.example.com:443",
    "username": "Secure",
    "password": "Yeah!",

    // h2s only provides some basic TLS settings. If you are an advanced user and
    // looking for other settings, you may use stunnel(1) to handle TLS instead,
    // and simply leave a naive TCP interface to h2s.
    "tlsConfig": {
      // If empty, serverName is set to the hostname from address.
      // Most users could just leave it empty.
      "serverName": "secure.proxy.example.com",

      // If you prefer to set a fingerprint instead of providing certs, you can
      // set this to true.
      // Do not set to true unless you know what you are doing.
      "insecureSkipVerify": false,
      // Server's SHA256 fingerprint, used to verify as an alternative to providing
      // the whole server certs, should be used with insecureSkipVerify to true.
      // If both rootCA and sha256Fingerprint are provided, they will both be
      // verified.
      //
      // An example to get fingerprint of a given cert:
      //     openssl x509 -fingerprint -sha256 -noout -in cert.cer | cut -f2 -d'=' | sed s/://g
      // or of a server with TLS enabled:
      //      openssl s_client -showcerts -connect example.com:443 < /dev/null | \
      //        openssl x509 -fingerprint -sha256 -noout | cut -f2 -d'=' | sed s/://g
      "sha256fingerprint": "22B975A1409850EF7F4522183E9C5A8955758FC899D70FE257112DA2FC430CCC",

      // rootCA is useful for self-signed certs. Be careful with it.
      // If the server has a trusted cert, you don't have to set it.
      "rootCA": "/path/to/the/ca/cert",

      // certFile and keyFile are advanced options for client authentication.
      // Most users could just leave it empty.
      "certFile": "/path/to/the/client/cert",
      "keyFile": "/path/to/the/client/key"
    }
  }],

  // accounts is an optional array of accounts for SOCKS5 authentication
  // with no accounts, authentication is disabled
  "accounts": [{
    "username": "test server",
    "password": "test"
  }],

  // timeout optionally sets timeout value when dialing to a upstream
  // default "20s"
  "timeout": "20s",
  // retries optionally specifies the max retries count of dialing to upstreams
  // default 3.
  "retries": 3
}
----

== Usage
[source,bash]
----
$ h2s [-config h2s.json]
----

== References
* https://tools.ietf.org/html/rfc1928[RFC 1928 - SOCKS Protocol Version 5]
* https://tools.ietf.org/html/rfc1929[RFC 1929 - Username/Password Authentication for SOCKS V5]
* https://tools.ietf.org/html/rfc7231[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]

== License
https://github.com/Equim-chan/h2s/blob/master/LICENSE[MIT]
Expand ▾ Collapse ▴

Documentation

Overview

Package h2s provides a tool that wraps one or multiple HTTP or HTTPS proxies into a SOCKS5 proxy. It does something like polipo and privoxy do, but in a reversed way.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

Account is used for SOCKS5 authentication.

type Config

type Config struct {
	// HTTP proxy upstreams.
	Upstreams []*Upstream `json:"upstreams"`

	// With no Accounts, authentication is disabled.
	Accounts []*Account `json:"accounts,omitempty"`

	// Timeout value when dialing to a upstream. Default "20s".
	Timeout string `json:"timeout"`

	// The max retries count of dialing to upstreams. Default 3.
	Retries *int `json:"retries"`
}

Config is used to configure an h2s Server.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is a SOCKS5 server that forward all incoming requests via Upstreams by HTTP/1.1 CONNECT.

func NewServer

func NewServer(c *Config) (*Server, error)

NewServer creates an h2s server instance.

func (*Server) Close

func (s *Server) Close() error

Close closes s. Already established connections will not be affected.

func (*Server) Serve

func (s *Server) Serve(conn net.Conn) error

Serve handles a net.Conn, reads request from it with SOCKS5 format, and dispatch the request via HTTP CONNECT. Serve closes conn whether an error occurs or connection is done. The caller must not use conn again.

type TLSConfig

type TLSConfig struct {
	// If empty, ServerName is set to the hostname from Address.
	// This is useful in some cases, for example a server behind Cloudflare,
	// since Cloudflare would simply reject CONNECT method.
	ServerName string `json:"serverName"`

	// If you prefer to set a fingerprint instead of providing certs, you can
	// set this to true.
	//
	// Do not set to true unless you know what you are doing.
	InsecureSkipVerify bool `json:"insecureSkipVerify"`
	// Server's SHA256 fingerprint, used to verify as an alternative to providing
	// the whole server certs.
	SHA256Fingerprint string `json:"sha256Fingerprint"`

	// For self-signed certs. Be careful.
	RootCA string `json:"rootCA"`

	// For client auth.
	CertFile string `json:"certFile"`
	KeyFile  string `json:"keyFile"`
}

TLSConfig is a simplified version of tls.Config

type Upstream

type Upstream struct {
	Address  string `json:"address"`
	Username string `json:"username,omitempty"`
	Password string `json:"password,omitempty"`

	// TLSConfig can be null.
	TLSConfig *TLSConfig `json:"tlsConfig"`
}

Upstream is a HTTPS proxy upstream that must support CONNECT method as defined in RFC 7231 section 4.3.6.

Directories

Path Synopsis
cmd/h2s