using proxy failed for checking cipher suit error PR_END_OF_FILE_ERROR on blocked host

Issue

I am trying to build a HTTPS proxy But i get PR_END_OF_FILE_ERROR in firefox that means failed to create a secure connection because no cipher suit found (more description).
What I do is after receiving CONNECT header from browser, I make a socket to that host, Connect successfully, and then write HTTP/1.1 200 Connection Established\r\n\r\n to broswer and then just pipe each other. It works OK on some host like google but not on blocked host (in my country) like youtube. I even changed DNS to 8.8.8.8 (google) but still doesn’t work. I think that browser tries to get something out of proxy but don’t know what or how.

func main() {
ln, _ := net.Listen("tcp", ":"+jjConfig.ListenPort)

    for {
        conn, _ := ln.Accept()
        err = conn.SetDeadline(time.Time{})
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println("Connection Received")
        go handleSocket(conn)
    }
}

func handleSocket(client_to_proxy net.Conn) {
    buffer := make([]byte, 9*1024)
    length, err := bufio.NewReader(client_to_proxy).Read(buffer)
    if err != nil {
        fmt.Println("ERR1 ", err)
        return
    }

    message := processReceived(buffer, length, jjConfig.ListenAuthentication, jjConfig.ListenUsers,
        jjConfig.ListenEncryption, jjConfig.ListenEncryptionKey)
    if message == "" {
        return
    }

    fmt.Println("MESSAGE IS: " + message)

    var host []string
    headers := strings.Split(message, "\r\n")
    for _, header := range headers {
        if strings.HasPrefix(header, "Host") {
            host = strings.Split(header, " ")
            fmt.Println("HOST ISSSSSSSS:" + host[1])
            break
        }
    }

    if strings.HasSuffix(host[1], "443") {
        proxy_to_server, e := net.Dial("tcp", host[1])
        if e != nil {
            fmt.Println("ERROR3 ", e)
            return
        }

        fmt.Println("CONNECTED TO: " + host[1])

        Writelength, err := client_to_proxy.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
        if err != nil {
            return
        }
        fmt.Println("WROTE 200 OK: " + strconv.Itoa(Writelength))
        if e != nil {
            fmt.Println("ERROR4 ", e)
            return
        }

        go exchange(client_to_proxy, proxy_to_server, host[1])
        exchange(proxy_to_server, client_to_proxy, host[1])

    } else {
        proxy_to_server, e := net.Dial("tcp", host[1]+":80")
        if e != nil {
            fmt.Println("ERROR5 ", e)
            return
        }
        Writelength, e := proxy_to_server.Write([]byte(message))
        fmt.Println("WROTE 80 Header: " + strconv.Itoa(Writelength))
        if e != nil {
            fmt.Println("ERROR6 ", e)
            return
        }

        go exchange(proxy_to_server, client_to_proxy, host[1])
        exchange(client_to_proxy, proxy_to_server, host[1])
    }
}

func exchange(src, dest net.Conn, host string) {
    defer func(src net.Conn) {
        err := src.Close()
        if err != nil {
            fmt.Println("ERRCPP2 ", err)
        }
    }(src)
    defer func(dest net.Conn) {
        err := dest.Close()
        if err != nil {
            fmt.Println("ERRCPP1 ", err)
        }
    }(dest)
    written, err := io.Copy(src, dest)
    if err != nil {
        fmt.Println("COPY ERROR SERVER IS "+host+": ", written, err)
        return
    }
}

Solution

Thanks to Steffen Ullrich, The problem was that we just encrypt headers from Browser to proxy server but no more. Because we though any thing after that will be encrypted by SSL/TLS. But after first connection to for example youtube, browser sends an encrypted message with "www.youtube.com" in plain text inside it. So GFW detect that and block message and message exchanging discontinued.

Answered By – forootan

Answer Checked By – Timothy Miller (GoLangFix Admin)

Leave a Reply

Your email address will not be published.