Skip to content

Commit

Permalink
Merge pull request #149 from projectdiscovery/issue-148-ztls-fallback
Browse files Browse the repository at this point in the history
add ztls fallback support
  • Loading branch information
Mzack9999 authored Jul 5, 2023
2 parents 806b4fc + 8838439 commit 4283c09
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ rawhttp is a Go package for making HTTP requests in a raw way.
- Forked and adapted from [https://github.com/gorilla/http](https://github.com/gorilla/http) and [https://github.com/valyala/fasthttp](https://github.com/valyala/fasthttp)
- The original idea is inspired by [@tomnomnom/rawhttp](https://github.com/tomnomnom/rawhttp) work


### ZTLS fallback support

### ZTLS Fallback

`rawhttp` by default fallbacks to using zcrypto when there is an error in TLS handshake (ex: ` insufficient security level` etc ). This is done to support older TLS versions and ciphers. This can be disabled by setting `rawhttp.DisableZtlsFallback` to `true` or by using `DISABLE_ZTLS_FALLBACK` environment variable. when falling back to ztls, `ChromeCiphers` are used



# Example

First you need to declare a `server`
Expand Down
57 changes: 47 additions & 10 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ package rawhttp
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"net/url"
"os"
"strings"
"sync"
"time"

"github.com/projectdiscovery/rawhttp/client"
"github.com/projectdiscovery/rawhttp/proxy"
ztls "github.com/zmap/zcrypto/tls"
)

// DisableZtlsFallback disables ztls fallback when tls handshake fails
// can also be set using the environment variable DISABLE_ZTLS_FALLBACK
var DisableZtlsFallback = false

// Dialer can dial a remote HTTP server.
type Dialer interface {
// Dial dials a remote http server returning a Conn.
Expand Down Expand Up @@ -111,21 +118,33 @@ func clientDial(protocol, addr string, timeout time.Duration, options *Options)
}

// https
tlsConfig := &tls.Config{InsecureSkipVerify: true}
tlsConfig := &tls.Config{InsecureSkipVerify: true, Renegotiation: tls.RenegotiateOnceAsClient}
if options.SNI != "" {
tlsConfig.ServerName = options.SNI
}

// currently fastdialer tls dial and ztls fallback are mutually exclusive
// TODO: add support for fallback in fastDialer.DialZTLS()
if options.FastDialer != nil {
return options.FastDialer.DialTLSWithConfig(ctx, "tcp", addr, tlsConfig)
} else if timeout > 0 {
conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil {
return nil, err
}
tlsConn := tls.Client(conn, tlsConfig)
return tlsConn, tlsConn.HandshakeContext(ctx)

}
return tls.Dial("tcp", addr, tlsConfig)

var dialer *net.Dialer
if timeout > 0 {
dialer = &net.Dialer{Timeout: timeout}
} else {
dialer = &net.Dialer{Timeout: 8 * time.Second} // should be more than enough
}
tlsConn, err := tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
if err != nil && !DisableZtlsFallback && !errors.Is(err, os.ErrDeadlineExceeded) {
return ztls.DialWithDialer(dialer, "tcp", addr, &ztls.Config{
CipherSuites: ztls.ChromeCiphers,
ServerName: tlsConfig.ServerName,
InsecureSkipVerify: true,
})
}
return tlsConn, err
}

// TlsHandshake tls handshake on a plain connection
Expand All @@ -152,7 +171,18 @@ func TlsHandshake(conn net.Conn, addr string, timeout time.Duration) (net.Conn,
ServerName: hostname,
})
if err := tlsConn.HandshakeContext(ctx); err != nil {
conn.Close()
if !errors.Is(err, os.ErrDeadlineExceeded) && !DisableZtlsFallback {
// fallback to ztls
ztlsConn := ztls.Client(conn, &ztls.Config{
InsecureSkipVerify: true,
ServerName: hostname,
CipherSuites: ztls.ChromeCiphers,
})
if err := ztlsConn.Handshake(); err != nil {
return nil, err
}
return ztlsConn, nil
}
return nil, err
}
return tlsConn, nil
Expand Down Expand Up @@ -181,3 +211,10 @@ func (c *conn) Release() {
addr := c.Conn.RemoteAddr().String()
c.dialer.conns[addr] = append(c.dialer.conns[addr], c)
}

func init() {
value := os.Getenv("DISABLE_ZTLS_FALLBACK")
if strings.EqualFold(value, "true") {
DisableZtlsFallback = true
}
}
31 changes: 31 additions & 0 deletions example/simple/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"flag"
"fmt"
"net/http/httputil"

"github.com/projectdiscovery/rawhttp"
)

var (
url string
short bool
)

func main() {
flag.StringVar(&url, "url", "https://scanme.sh", "URL to fetch")
flag.BoolVar(&short, "short", false, "Skip printing http response body")
flag.Parse()

client := rawhttp.NewClient(rawhttp.DefaultOptions)
resp, err := client.Get(url)
if err != nil {
panic(err)
}
bin, err := httputil.DumpResponse(resp, !short)
if err != nil {
panic(err)
}
fmt.Println(string(bin))
}

0 comments on commit 4283c09

Please sign in to comment.