astraproxy/utils.go

192 lines
3.6 KiB
Go
Raw Normal View History

2020-05-19 21:53:13 +02:00
package main
import (
2021-02-26 08:09:55 +01:00
"bufio"
"context"
"crypto/tls"
"crypto/x509"
"errors"
"io"
"io/ioutil"
2021-02-26 08:30:18 +01:00
"log"
2021-02-26 08:09:55 +01:00
"net"
"net/http"
2021-02-26 08:30:18 +01:00
"strings"
2021-02-26 08:09:55 +01:00
"sync"
"time"
2020-05-19 21:53:13 +02:00
)
2020-05-22 20:02:08 +02:00
const COPY_BUF = 128 * 1024
2020-05-19 21:53:13 +02:00
func proxy(ctx context.Context, left, right net.Conn) {
2021-02-26 08:09:55 +01:00
wg := sync.WaitGroup{}
cpy := func(dst, src net.Conn) {
defer wg.Done()
io.Copy(dst, src)
dst.Close()
}
wg.Add(2)
go cpy(left, right)
go cpy(right, left)
groupdone := make(chan struct{}, 1)
go func() {
wg.Wait()
groupdone <- struct{}{}
}()
select {
case <-ctx.Done():
left.Close()
right.Close()
case <-groupdone:
return
}
<-groupdone
return
2020-05-19 21:53:13 +02:00
}
2020-05-24 14:24:11 +02:00
func proxyh2(ctx context.Context, leftreader io.ReadCloser, leftwriter io.Writer, right net.Conn) {
2021-02-26 08:09:55 +01:00
wg := sync.WaitGroup{}
ltr := func(dst net.Conn, src io.Reader) {
defer wg.Done()
io.Copy(dst, src)
dst.Close()
}
rtl := func(dst io.Writer, src io.Reader) {
defer wg.Done()
copyBody(dst, src)
}
wg.Add(2)
go ltr(right, leftreader)
go rtl(leftwriter, right)
groupdone := make(chan struct{}, 1)
go func() {
wg.Wait()
groupdone <- struct{}{}
}()
select {
case <-ctx.Done():
leftreader.Close()
right.Close()
case <-groupdone:
return
}
<-groupdone
return
2020-05-24 14:24:11 +02:00
}
2020-05-19 21:53:13 +02:00
// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
"Connection",
"Keep-Alive",
"Proxy-Authenticate",
"Proxy-Connection",
2021-02-26 08:09:55 +01:00
"Proxy-Authorization",
2020-05-19 21:53:13 +02:00
"Te", // canonicalized version of "TE"
"Trailers",
"Transfer-Encoding",
"Upgrade",
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
func delHopHeaders(header http.Header) {
for _, h := range hopHeaders {
header.Del(h)
}
}
func hijack(hijackable interface{}) (net.Conn, *bufio.ReadWriter, error) {
2021-02-26 08:09:55 +01:00
hj, ok := hijackable.(http.Hijacker)
if !ok {
return nil, nil, errors.New("Connection doesn't support hijacking")
}
conn, rw, err := hj.Hijack()
if err != nil {
return nil, nil, err
}
var emptytime time.Time
err = conn.SetDeadline(emptytime)
if err != nil {
conn.Close()
return nil, nil, err
}
return conn, rw, nil
2020-05-19 21:53:13 +02:00
}
2020-05-19 23:53:32 +02:00
func flush(flusher interface{}) bool {
2021-02-26 08:09:55 +01:00
f, ok := flusher.(http.Flusher)
if !ok {
return false
}
f.Flush()
return true
2020-05-19 23:53:32 +02:00
}
2020-05-22 20:02:08 +02:00
func copyBody(wr io.Writer, body io.Reader) {
2021-02-26 08:09:55 +01:00
buf := make([]byte, COPY_BUF)
for {
bread, read_err := body.Read(buf)
var write_err error
if bread > 0 {
_, write_err = wr.Write(buf[:bread])
flush(wr)
}
if read_err != nil || write_err != nil {
break
}
}
2020-05-22 20:02:08 +02:00
}
2020-05-24 00:18:01 +02:00
func makeServerTLSConfig(certfile, keyfile, cafile string) (*tls.Config, error) {
2021-02-26 08:09:55 +01:00
var cfg tls.Config
cert, err := tls.LoadX509KeyPair(certfile, keyfile)
if err != nil {
return nil, err
}
cfg.Certificates = []tls.Certificate{cert}
if cafile != "" {
roots := x509.NewCertPool()
certs, err := ioutil.ReadFile(cafile)
if err != nil {
return nil, err
}
if ok := roots.AppendCertsFromPEM(certs); !ok {
return nil, errors.New("Failed to load CA certificates")
}
cfg.ClientCAs = roots
cfg.ClientAuth = tls.VerifyClientCertIfGiven
}
return &cfg, nil
2020-05-24 00:18:01 +02:00
}
2021-02-26 08:30:18 +01:00
func makeCipherList(ciphers string) []uint16 {
if ciphers == "" {
return nil
}
cipherIDs := make(map[string]uint16)
for _, cipher := range tls.CipherSuites() {
cipherIDs[cipher.Name] = cipher.ID
}
cipherNameList := strings.Split(ciphers, ":")
cipherIDList := make([]uint16, 0, len(cipherNameList))
for _, name := range cipherNameList {
id, ok := cipherIDs[name]
if !ok {
log.Printf("WARNING: Unknown cipher \"%s\"", name)
}
cipherIDList = append(cipherIDList, id)
}
return cipherIDList
}