Giter VIP home page Giter VIP logo

bddjr / hlfhr Goto Github PK

View Code? Open in Web Editor NEW
1.0 1.0 1.0 55 KB

🚀HTTPS Listener For HTTP Redirect✔ If a user accesses an https port using http, the server returns 302 redirection. 当用户使用 http 协议访问 https 端口时,服务器返回302重定向。

License: BSD 3-Clause "New" or "Revised" License

Go 98.07% HTML 1.93%
go go-mod golang https redirect https-server httpserver ssl go-module go-package

hlfhr's Introduction

HTTPS Listener For HTTP Redirect

这个 mod 通过劫持 net.Conn 实现了一个功能:
当用户使用 http 协议访问 https 端口时,服务器返回302重定向。

This mod implements a feature by hijacking net.Conn :
If a user accesses an https port using http, the server returns 302 redirection.

Related Issue:
net/http: configurable error message for Client sent an HTTP request to an HTTPS server. #49310


Get

go get github.com/bddjr/hlfhr

Example

See example/main.go

Example:

var srv *hlfhr.Server

func main() {
	// Use hlfhr.New
	srv = hlfhr.New(&http.Server{
		Addr: ":5678",
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Write something...
		}),
		ReadHeaderTimeout: 10 * time.Second,
		IdleTimeout:       10 * time.Second,
	})
	// Then just use it like http.Server .

	err := srv.ListenAndServeTLS("localhost.crt", "localhost.key")
	fmt.Println(err)
}
var l net.Listener
var srv *http.Server

func main() {
	srv = &http.Server{
		Addr: ":5678",
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Write something...
		}),
		ReadHeaderTimeout: 10 * time.Second,
		IdleTimeout:       10 * time.Second,
	}

	var err error
	l, err = net.Listen("tcp", srv.Addr)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer l.Close()

	// Use hlfhr.NewListener
	l = hlfhr.NewListener(l, srv, nil)

	err = srv.ServeTLS(l, "localhost.crt", "localhost.key")
	fmt.Println(err)
}

Run:

git clone https://github.com/bddjr/hlfhr
cd hlfhr
cd example

go build
./example

  test:
  cmd /C curl -v -k -L http://localhost:5678/

2024/06/20 11:50:09 http: TLS handshake error from [::1]:60470: hlfhr: Client sent an HTTP request to an HTTPS server

Logic

See request

HTTPS Server Start -> Hijacking net.Listener.Accept

Client HTTPS

Accept hijacking net.Conn.Read -> First byte not looks like HTTP -> ✅Continue...

Client HTTP/1.1

Accept hijacking net.Conn.Read -> First byte looks like HTTP -> Read request -> Found Host header -> HttpOnHttpsPortErrorHandler -> Close connect.

If handler nil -> 🔄302 Redirect -> Close connect.

Client HTTP/???

Accept hijacking net.Conn.Read -> First byte looks like HTTP -> Read request -> Missing Host header -> ❌400 Bad Request -> Close connect.


Option Example

HttpOnHttpsPortErrorHandler

// Default
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	hlfhr.RedirectToHttps(w, r, 302)
})
// Check Host Header
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	switch hlfhr.Hostname(r.Host) {
	case "localhost":
		hlfhr.RedirectToHttps(w, r, 302)
	case "www.localhost", "127.0.0.1":
		hlfhr.Redirect(w, 302, "https://"+hlfhr.ReplaceHostname(r.Host, "localhost")+r.URL.RequestURI())
	default:
		w.WriteHeader(421)
	}
})
// Script Redirect
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(400)
	io.WriteString(w, "<script> location.protocol = 'https:' </script>")
})
// Keep Alive
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Connection", "keep-alive")
	w.WriteHeader(400)
	io.WriteString(w, "Hello hlfhr")
})

Feature Example

New

srv := hlfhr.New(&http.Server{})

NewServer

srv := hlfhr.NewServer(&http.Server{})

Server.IsShuttingDown

var srv *hlfhr.Server
isShuttingDown := srv.IsShuttingDown()

Server.NewListener

var l net.Listener
var srv *http.Server
l = hlfhr.New(srv).NewListener(l)

NewListener

var l net.Listener
var srv *http.Server
var h http.Handler
l = hlfhr.NewListener(c, srv, h)

IsMyListener

var l net.Listener
isHlfhrListener := hlfhr.IsMyListener(l)

NewConn

var c net.Conn
var srv *http.Server
var h http.Handler
c = hlfhr.NewConn(c, srv, h)

IsMyConn

var c net.Conn
isHlfhrConn := hlfhr.IsMyConn(c)

NewResponse

resp := hlfhr.NewResponse()

NewResponseWriter

var c net.Conn
w := hlfhr.NewResponseWriter(c, nil)
hw := http.ResponseWriter(w)

http.NewResponseController

var w http.ResponseWriter
rc := http.NewResponseController(w)

Redirect

var w http.ResponseWriter
hlfhr.Redirect(w, 302, "https://example.com/")

RedirectToHttps

var w http.ResponseWriter
var r *http.Request
hlfhr.RedirectToHttps(w, r, 302)

SplitHostnamePort

hostname, port := hlfhr.SplitHostnamePort("[::1]:5678")
// hostname: [::1]
// port: 5678

Hostname

hostname := hlfhr.Hostname("[::1]:5678")
// hostname: [::1]

Port

port := hlfhr.Port("[::1]:5678")
// port: 5678

HostnameAppendPort

Host := hlfhr.HostnameAppendPort("[::1]", "5678")
// Host: [::1]:5678

ReplaceHostname

Host := hlfhr.ReplaceHostname("[::1]:5678", "localhost")
// Host: localhost:5678

ReplacePort

Host := hlfhr.ReplacePort("[::1]:5678", "7890")
// Host: [::1]:7890

Ipv6CutPrefixSuffix

v6 := hlfhr.Ipv6CutPrefixSuffix("[::1]")
// v6: ::1

License

BSD-3-clause license

hlfhr's People

Contributors

bddjr avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

amon1axez

hlfhr's Issues

笔记

昨天我甚至想看看go的http标准库还能不能改的更规范点,通过正确的途径解析发送到HTTPS端口的HTTP请求,然而看了几遍后放弃了。

这东西写的时候根本没考虑从TLS握手回退到HTTP1.1,标准库就只是简单写入400然后关闭连接,这东西真正改起来很费精力,所以这问题从2021年到现在,标准库还是没解决,我只能在这基础上写个第三方库继续堆屎

大致描述一下模块干了什么

大致描述一下模块干了什么

核心部分是 listener.go ,一些原理主要参考了golang标准库的 tls.NewListener


connRead 函数:
检测到是tcp连接第一次读取,
读取前 5 个字节,并检测会不会被 net/http 标准库认为是一个http请求,

如果会,(HTTP/1.1)继续读取 4096-5 个字节并缓存(再从标准库转一圈就会来到 Write 函数),
否则,(HTTPS)继续读取 576-5 个字节,不缓存。


connWrite 函数:
检测到是tcp连接第一次写入,
检测有没有来自 Read 的缓存,
然后检测是不是 net/http 默认的写入行为(HTTP/1.0 400 Bad Request),

如果以上条件符合,则执行:
检测有没有自定义的handler,
如果有,执行handler然后退出,
否则,执行这个模块内置的重定向行为。


其余的 Listener 类型是用来修改 Accept 行为,在接受新的连接时,注入自定义的 conn

readreq.go 用来从字节组解析所需的请求内容,给 listener.go 用的

server.goServeTLS 的时候将默认的 net.Listener 变成自己的 Listener ,再执行 net/http 标准库的 srv.ServeTLS

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.