建立 HTTPS 代理失败,错误为 SSL_ERROR_BAD_MAC_READ。

huangapple go评论115阅读模式
英文:

building https proxy failed with error SSL_ERROR_BAD_MAC_READ

问题

我正在尝试使用Golang创建一个类似于链接中的HTTP/HTTPS代理。以下是我的全部代码:

首先从浏览器获取命令。如果是CONNECT,则表示HTTPS连接,创建一个简单的TCP套接字并让浏览器继续连接,然后将每个连接进行管道传输。

package main

import (
	"bufio"
	"fmt"
	"net"
	"strings"
)

func main() {
	fmt.Println("启动服务器...")

	ln, _ := net.Listen("tcp", ":8000")

	conn, _ := ln.Accept()
	handleSocket(conn)

}

func handleSocket(client_to_proxy net.Conn) {
	message, e := bufio.NewReader(client_to_proxy).ReadString('\n')
	message = strings.ReplaceAll(message, "\r\n", "")
	if e != nil {
		fmt.Println("错误1 ", e)
		return
	}

	splited := strings.Split(message, " ")
	host := strings.Split(splited[1], ":")
	if splited[0] == "CONNECT" {
		proxy_to_server, e := net.Dial("tcp", splited[1])
		if e != nil {
			fmt.Println("错误2 ", e)
			return
		}
		lenn, e := client_to_proxy.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
		if e != nil {
			fmt.Println("错误8 ", e)
			return
		}
		fmt.Println(lenn)

		readAll(client_to_proxy, proxy_to_server)

	} else if splited[0] == "GET" {
		remote_conn, e := net.Dial("tcp", strings.Replace(splited[1][:len(splited[1])-1], "http://", "", 2)+":80")
		if e != nil {
			fmt.Println("错误7 ", e)
			return
		}
		_, e = remote_conn.Write([]byte("GET / " + splited[2] + "\r\n" + "Host: " + host[0] + "\r\n\r\n"))
		if e != nil {
			fmt.Println("错误6 ", e)
			return
		}
		writeAll(client_to_proxy, remote_conn)
	}
}

func writeAll(client_to_proxy net.Conn, proxy_to_server net.Conn) {
	buffer := make([]byte, 32*1024)
	for {
		readLeng, err := proxy_to_server.Read(buffer)
		if err != nil {
			fmt.Println("错误9 ", err)
			return
		}
		if readLeng > 0 {
			_, err := client_to_proxy.Write(buffer)
			if err != nil {
				fmt.Println("错误4 ", err)
				return
			}
		}
	}
}

func readAll(client_to_proxy net.Conn, proxy_to_server net.Conn) {
	buffer := make([]byte, 32*1024)
	go writeAll(client_to_proxy, proxy_to_server)

	for {
		read, err := client_to_proxy.Read(buffer)
		if err != nil {
			return
		}
		if read > 0 {
			_, err := proxy_to_server.Write(buffer)
			if err != nil {
				fmt.Println("错误5 ", err)
				return
			}
		}
	}
}

它可以正常处理HTTP请求,但是在尝试使用Firefox进行HTTPS请求时,我收到以下错误:

安全连接失败

在与www.google.com的连接过程中发生错误。SSL接收到具有错误消息认证码的记录。

错误代码:SSL_ERROR_BAD_MAC_READ

英文:

I am trying to make an HTTP/HTTPS proxy with Golang like this link.
This is all my code :
First get command from browser. If it's CONNECT mean HTTPS and make simple TCP socket and let browser continue it. then pipe each connection together.

package main
import (
"bufio"
"fmt"
"net"
"strings"
)
func main() {
fmt.Println("Start server...")
ln, _ := net.Listen("tcp", ":8000")
conn, _ := ln.Accept()
handleSocket(conn)
}
func handleSocket(client_to_proxy net.Conn) {
message, e := bufio.NewReader(client_to_proxy).ReadString('\n')
message = strings.ReplaceAll(message, "\r\n", "")
if e != nil {
fmt.Println("ERROR1 ", e)
return
}
splited := strings.Split(message, " ")
host := strings.Split(splited[1], ":")
if splited[0] == "CONNECT" {
proxy_to_server, e := net.Dial("tcp", splited[1])
if e != nil {
fmt.Println("ERROR2 ", e)
return
}
lenn, e := client_to_proxy.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
if e != nil {
fmt.Println("ERROR8 ", e)
return
}
fmt.Println(lenn)
readAll(client_to_proxy, proxy_to_server)
} else if splited[0] == "GET" {
remote_conn, e := net.Dial("tcp", strings.Replace(splited[1][:len(splited[1])-1], "http://", "", 2)+":80")
if e != nil {
fmt.Println("ERROR7 ", e)
return
}
_, e = remote_conn.Write([]byte("GET / " + splited[2] + "\r\n" + "Host: " + host[0] + "\r\n\r\n"))
if e != nil {
fmt.Println("ERROR6 ", e)
return
}
writeAll(client_to_proxy, remote_conn)
}
}
func writeAll(client_to_proxy net.Conn, proxy_to_server net.Conn) {
buffer := make([]byte, 32*1024)
for {
readLeng, err := proxy_to_server.Read(buffer)
if err != nil {
fmt.Println("ERROR9 ", err)
return
}
if readLeng > 0 {
_, err := client_to_proxy.Write(buffer)
if err != nil {
fmt.Println("ERR4 ", err)
return
}
}
}
}
func readAll(client_to_proxy net.Conn, proxy_to_server net.Conn) {
buffer := make([]byte, 32*1024)
go writeAll(client_to_proxy, proxy_to_server)
for {
read, err := client_to_proxy.Read(buffer)
if err != nil {
return
}
if read > 0 {
_, err := proxy_to_server.Write(buffer)
if err != nil {
fmt.Println("ERR5 ", err)
return
}
}
}
}

It works OK with HTTP but when trying for HTTPS in Firefox, I receive this error:

>Secure Connection Failed

>An error occurred during a connection to www.google.com. SSL received a record with an incorrect Message Authentication Code.

>Error code: SSL_ERROR_BAD_MAC_READ

答案1

得分: 0

像所有的HTTP请求一样,CONNECT请求以一个多行请求头开始,该请求头以只包含\r\n的行结束。但是你只读取了它的第一行:

> message, e := bufio.NewReader(client_to_proxy).ReadString('\n')

请求的其余部分被发送到服务器,服务器可能会返回一些错误,因为这不是预期的TLS握手的开始。TLS握手的开始只会在请求头之后出现。服务器返回的错误然后被转发给客户端,并被解释为TLS消息 - 这被视为损坏的消息,因此出现了"bad mac"。

> readAll(client_to_proxy, proxy_to_server)

你需要先读取完整的请求头,然后再将客户端和服务器之间的所有内容转发给服务器,而不是转发除了请求的第一行之外的所有剩余数据。

英文:

Like all HTTP requests the CONNECT request starts with a multi-line request header which ends with a line consisting of only \r\n. But you only read the first line of it:

> message, e := bufio.NewReader(client_to_proxy).ReadString('\n')

The rest of the request is send to the server, which likely returns some error, since this is not the expected start of a TLS handshake. This start of a TLS handshake only comes after the request header. The error returned by the server is then forwarded to the client and interpreted as TLS message - which is seen as a corrupt message, hence "bad mac".

> readAll(client_to_proxy, proxy_to_server)

Instead of forwarding all remaining data (i.e. everything except the first line of the request) to the server you need to first read the full request header and only then forward everything between client and server.

答案2

得分: 0

感谢@steffen-ullrich,这是最终的解决方案,适用于http/https:

package main

import (
	"fmt"
	"net"
	"strings"
)

func main() {
	fmt.Println("启动服务器...")

	ln, _ := net.Listen("tcp", ":8000")

	for {
		conn, _ := ln.Accept()
		handleSocket(conn)
	}
}

func handleSocket(client_to_proxy net.Conn) {
	buffer := make([]byte, 32*1024)
	_, e := client_to_proxy.Read(buffer)
	if e != nil {
		fmt.Println("错误1 ", e)
		return
	}
	message := string(buffer)
	a := strings.Count(message, "\r\n")
	fmt.Println(message)
	fmt.Println(a)
	if e != nil {
		fmt.Println("错误1 ", e)
		return
	}

	splited := strings.Split(message, " ")
	//host := strings.Split(splited[1], ":")
	if splited[0] == "CONNECT" {
		//message = strings.Replace(message, "CONNECT", "GET", 1)
		proxy_to_server, e := net.Dial("tcp", splited[1])
		if e != nil {
			fmt.Println("错误2 ", e)
			return
		}
		//_, e = proxy_to_server.Write([]byte(message))
		//if e != nil {
		//	fmt.Println("错误2 ", e)
		//	return
		//}
		lenn, e := client_to_proxy.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
		if e != nil {
			fmt.Println("错误8 ", e)
			return
		}
		fmt.Println(lenn)

		read443(client_to_proxy, proxy_to_server)
	} else if splited[0] == "GET" {
		host1 := strings.Replace(splited[1], "http://", "", 1)
		host2 := host1[:len(host1)-1]
		var final_host string
		if strings.LastIndexAny(host2, "/") > 0 {
			final_host = host2[:strings.LastIndexAny(host2, "/")]
		} else {
			final_host = host2
		}
		proxy_to_server, e := net.Dial("tcp", final_host+":80")
		if e != nil {
			fmt.Println("错误7 ", e)
			return
		}
		_, e = proxy_to_server.Write([]byte(message))
		if e != nil {
			fmt.Println("错误6 ", e)
			return
		}

		write80(client_to_proxy, proxy_to_server)
	}
}

func write80(client_to_proxy net.Conn, proxy_to_server net.Conn) {
	buffer := make([]byte, 64*1024)

	readLeng, err := proxy_to_server.Read(buffer)
	if err != nil {
		fmt.Println("错误9 ", err)
		return
	}
	fmt.Println("从服务器写入:")
	fmt.Println(string(buffer[:readLeng]))
	if readLeng > 0 {
		_, err := client_to_proxy.Write(buffer[:readLeng])
		if err != nil {
			fmt.Println("错误4 ", err)
			return
		}
	}

	go read80(client_to_proxy, proxy_to_server)
	for {
		readLeng, err := proxy_to_server.Read(buffer)
		if err != nil {
			fmt.Println("错误10 ", err)
			return
		}
		fmt.Println("从服务器写入:")
		fmt.Println(string(buffer[:readLeng]))
		if readLeng > 0 {
			_, err := client_to_proxy.Write(buffer[:readLeng])
			if err != nil {
				fmt.Println("错误4 ", err)
				return
			}
		}
	}
}

func read80(client_to_proxy net.Conn, proxy_to_server net.Conn) {
	buffer := make([]byte, 32*1024)

	for {
		readLeng, err := client_to_proxy.Read(buffer)
		if err != nil {
			return
		}
		fmt.Println("从客户端读取:")
		fmt.Println(string(buffer[:readLeng]))
		if readLeng > 0 {
			_, err := proxy_to_server.Write(buffer[:readLeng])
			if err != nil {
				fmt.Println("错误5 ", err)
				return
			}
		}
	}
}

func write443(client_to_proxy net.Conn, proxy_to_server net.Conn) {
	buffer := make([]byte, 32*1024)
	for {
		readLeng, err := proxy_to_server.Read(buffer)
		if err != nil {
			fmt.Println("错误10 ", err)
			return
		}
		fmt.Println("从服务器写入:")
		fmt.Println(string(buffer[:readLeng]))
		if readLeng > 0 {
			_, err := client_to_proxy.Write(buffer[:readLeng])
			if err != nil {
				fmt.Println("错误4 ", err)
				return
			}
		}
	}
}

func read443(client_to_proxy net.Conn, proxy_to_server net.Conn) {
	buffer := make([]byte, 32*1024)

	readLeng, err := client_to_proxy.Read(buffer)
	if err != nil {
		return
	}
	fmt.Println("从客户端读取:")
	fmt.Println(string(buffer[:readLeng]))
	if readLeng > 0 {
		_, err := proxy_to_server.Write(buffer[:readLeng])
		if err != nil {
			fmt.Println("错误5 ", err)
			return
		}
	}

	go write443(client_to_proxy, proxy_to_server)

	for {
		readLeng, err := client_to_proxy.Read(buffer)
		if err != nil {
			return
		}
		fmt.Println("从客户端读取:")
		fmt.Println(string(buffer[:readLeng]))
		if readLeng > 0 {
			_, err := proxy_to_server.Write(buffer[:readLeng])
			if err != nil {
				fmt.Println("错误5 ", err)
				return
			}
		}
	}
}

希望对你有帮助!

英文:

Many Thanks to @steffen-ullrich, This is final solution for who comes later. works for http/https:

package main
import (
"fmt"
"net"
"strings"
)
func main() {
fmt.Println("Start server...")
ln, _ := net.Listen("tcp", ":8000")
for {
conn, _ := ln.Accept()
handleSocket(conn)
}
}
func handleSocket(client_to_proxy net.Conn) {
buffer := make([]byte, 32*1024)
_, e := client_to_proxy.Read(buffer)
if e != nil {
fmt.Println("ERROR1 ", e)
return
}
message := string(buffer)
a := strings.Count(message, "\r\n")
fmt.Println(message)
fmt.Println(a)
if e != nil {
fmt.Println("ERROR1 ", e)
return
}
splited := strings.Split(message, " ")
//host := strings.Split(splited[1], ":")
if splited[0] == "CONNECT" {
//message = strings.Replace(message, "CONNECT", "GET", 1)
proxy_to_server, e := net.Dial("tcp", splited[1])
if e != nil {
fmt.Println("ERROR2 ", e)
return
}
//_, e = proxy_to_server.Write([]byte(message))
//if e != nil {
//	fmt.Println("ERROR2 ", e)
//	return
//}
lenn, e := client_to_proxy.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
if e != nil {
fmt.Println("ERROR8 ", e)
return
}
fmt.Println(lenn)
read443(client_to_proxy, proxy_to_server)
} else if splited[0] == "GET" {
host1 := strings.Replace(splited[1], "http://", "", 1)
host2 := host1[:len(host1)-1]
var final_host string
if strings.LastIndexAny(host2, "/") > 0 {
final_host = host2[:strings.LastIndexAny(host2, "/")]
} else {
final_host = host2
}
proxy_to_server, e := net.Dial("tcp", final_host+":80")
if e != nil {
fmt.Println("ERROR7 ", e)
return
}
_, e = proxy_to_server.Write([]byte(message))
if e != nil {
fmt.Println("ERROR6 ", e)
return
}
write80(client_to_proxy, proxy_to_server)
}
}
func write80(client_to_proxy net.Conn, proxy_to_server net.Conn) {
buffer := make([]byte, 64*1024)
readLeng, err := proxy_to_server.Read(buffer)
if err != nil {
fmt.Println("ERROR9 ", err)
return
}
fmt.Println("WRIIIIIIIIIIIIIIIIIIIIIIT from server:")
fmt.Println(string(buffer[:readLeng]))
if readLeng > 0 {
_, err := client_to_proxy.Write(buffer[:readLeng])
if err != nil {
fmt.Println("ERR4 ", err)
return
}
}
go read80(client_to_proxy, proxy_to_server)
for {
readLeng, err := proxy_to_server.Read(buffer)
if err != nil {
fmt.Println("ERROR10 ", err)
return
}
fmt.Println("WRIIIIIIIIIIIIIIIIIIIIIIT from server:")
fmt.Println(string(buffer[:readLeng]))
if readLeng > 0 {
_, err := client_to_proxy.Write(buffer[:readLeng])
if err != nil {
fmt.Println("ERR4 ", err)
return
}
}
}
}
func read80(client_to_proxy net.Conn, proxy_to_server net.Conn) {
buffer := make([]byte, 32*1024)
for {
readLeng, err := client_to_proxy.Read(buffer)
if err != nil {
return
}
fmt.Println("REEEEEEEEEEEEEEEEEEEEEEED from client:")
fmt.Println(string(buffer[:readLeng]))
if readLeng > 0 {
_, err := proxy_to_server.Write(buffer[:readLeng])
if err != nil {
fmt.Println("ERR5 ", err)
return
}
}
}
}
func write443(client_to_proxy net.Conn, proxy_to_server net.Conn) {
buffer := make([]byte, 32*1024)
for {
readLeng, err := proxy_to_server.Read(buffer)
if err != nil {
fmt.Println("ERROR10 ", err)
return
}
fmt.Println("WRIIIIIIIIIIIIIIIIIIIIIIT from server:")
fmt.Println(string(buffer[:readLeng]))
if readLeng > 0 {
_, err := client_to_proxy.Write(buffer[:readLeng])
if err != nil {
fmt.Println("ERR4 ", err)
return
}
}
}
}
func read443(client_to_proxy net.Conn, proxy_to_server net.Conn) {
buffer := make([]byte, 32*1024)
readLeng, err := client_to_proxy.Read(buffer)
if err != nil {
return
}
fmt.Println("REEEEEEEEEEEEEEEEEEEEEEED from client:")
fmt.Println(string(buffer[:readLeng]))
if readLeng > 0 {
_, err := proxy_to_server.Write(buffer[:readLeng])
if err != nil {
fmt.Println("ERR5 ", err)
return
}
}
go write443(client_to_proxy, proxy_to_server)
for {
readLeng, err := client_to_proxy.Read(buffer)
if err != nil {
return
}
fmt.Println("REEEEEEEEEEEEEEEEEEEEEEED from client:")
fmt.Println(string(buffer[:readLeng]))
if readLeng > 0 {
_, err := proxy_to_server.Write(buffer[:readLeng])
if err != nil {
fmt.Println("ERR5 ", err)
return
}
}
}
}

huangapple
  • 本文由 发表于 2022年10月25日 03:04:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/74185665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定