123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package webtunnel
- import (
- "errors"
- "fmt"
- "log"
- "net"
- "net/url"
- "strings"
- pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
- "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/webtunnel/transport/httpupgrade"
- "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/webtunnel/transport/tls"
- "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
- )
- type clientConfig struct {
- RemoteAddresses []string
- Path string
- TLSKind string
- TLSServerName string
- UTLSFingerprint string
- }
- type clientFactory struct {
- parent base.Transport
- }
- func (c *clientFactory) Transport() base.Transport {
- return c.parent
- }
- func (c *clientFactory) ParseArgs(args *pt.Args) (interface{}, error) {
- i, err := c.parseArgs(args)
- if err != nil {
- pt.Log(pt.LogSeverityError, fmt.Sprintf("Error parsing args: %v", err))
- return nil, err
- }
- return i, nil
- }
- func (c *clientFactory) parseArgs(args *pt.Args) (interface{}, error) {
- var config clientConfig
- if urlStr, ok := args.Get("url"); ok {
- url, err := url.Parse(urlStr)
- if err != nil {
- return nil, fmt.Errorf("url parse error: %s", err)
- }
- defaultPort := ""
- switch url.Scheme {
- case "https":
- config.TLSKind = "tls"
- defaultPort = "443"
- case "http":
- config.TLSKind = ""
- defaultPort = "80"
- default:
- return nil, fmt.Errorf("url parse error: unknown scheme")
- }
- config.Path = strings.TrimPrefix(url.EscapedPath(), "/")
- config.TLSServerName = url.Hostname()
- port := url.Port()
- if port == "" {
- port = defaultPort
- }
- config.RemoteAddresses, err = getAddressesFromHostname(url.Hostname(), port)
- if err != nil {
- log.Println(err)
- return nil, errors.New("")
- }
- config.TLSServerName = url.Hostname()
- }
- if tlsServerName, ok := args.Get("servername"); ok {
- config.TLSServerName = tlsServerName
- }
- if uTLSFingerprint, ok := args.Get("utls"); ok {
- config.UTLSFingerprint = uTLSFingerprint
- if config.UTLSFingerprint == "" {
- config.UTLSFingerprint = "hellorandomizednoalpn"
- }
- if config.UTLSFingerprint == "none" {
- config.UTLSFingerprint = ""
- }
- }
- return config, nil
- }
- func (c *clientFactory) Dial(network, address string, dialFn base.DialFunc, args interface{}) (net.Conn, error) {
- conn, err := c.dial(network, address, dialFn, args)
- if err != nil {
- pt.Log(pt.LogSeverityError, fmt.Sprintf("Error dialing: %v", err))
- return nil, err
- }
- return conn, nil
- }
- func (c *clientFactory) dial(network, address string, dialFn base.DialFunc, args interface{}) (net.Conn, error) {
- config := args.(clientConfig)
- var conn net.Conn
- for _, addr := range config.RemoteAddresses {
- if tcpConn, err := dialFn("tcp", addr); err == nil {
- conn = tcpConn
- break
- }
- }
- if conn == nil {
- return nil, fmt.Errorf("Can't connect to %v", config.RemoteAddresses)
- }
- if config.TLSKind != "" {
- conf := &tls.Config{ServerName: config.TLSServerName}
- if config.UTLSFingerprint == "" {
- if tlsTransport, err := tls.NewTLSTransport(conf); err != nil {
- return nil, err
- } else {
- if tlsConn, err := tlsTransport.Client(conn); err != nil {
- return nil, err
- } else {
- conn = tlsConn
- }
- }
- } else {
- utlsConfig := &uTLSConfig{ServerName: config.TLSServerName, uTLSFingerprint: config.UTLSFingerprint}
- if utlsTransport, err := newUTLSTransport(utlsConfig); err != nil {
- return nil, err
- } else {
- if utlsConn, err := utlsTransport.Client(conn); err != nil {
- return nil, err
- } else {
- conn = utlsConn
- }
- }
- }
- }
- upgradeConfig := httpupgrade.Config{Path: config.Path, Host: config.TLSServerName}
- if httpupgradeTransport, err := httpupgrade.NewHTTPUpgradeTransport(&upgradeConfig); err != nil {
- return nil, err
- } else {
- if httpUpgradeConn, err := httpupgradeTransport.Client(conn); err != nil {
- return nil, err
- } else {
- conn = httpUpgradeConn
- }
- }
- return conn, nil
- }
- // Not yet implemented
- func (cf *clientFactory) OnEvent(f func(base.TransportEvent)) {}
- func getAddressesFromHostname(hostname, port string) ([]string, error) {
- addresses := []string{}
- addr, err := net.LookupHost(hostname)
- if err != nil {
- return addresses, fmt.Errorf("Lookup error for host %s: %v", hostname, err)
- }
- for _, a := range addr {
- ip := net.ParseIP(a)
- if ip == nil || ip.IsLoopback() || ip.IsUnspecified() || ip.IsMulticast() || ip.IsLinkLocalUnicast() || ip.IsPrivate() {
- continue
- }
- if ip.To4() != nil {
- addresses = append(addresses, a+":"+port)
- } else {
- addresses = append(addresses, "["+a+"]:"+port)
- }
- }
- if len(addresses) == 0 {
- return addresses, fmt.Errorf("Could not find any valid IP for %s", hostname)
- }
- return addresses, nil
- }
|