WIP
This commit is contained in:
111
handlers/dns.go
111
handlers/dns.go
@@ -1,111 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/play-with-docker/play-with-docker/config"
|
||||
)
|
||||
|
||||
func DnsRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
if len(r.Question) > 0 && config.NameFilter.MatchString(r.Question[0].Name) {
|
||||
// this is something we know about and we should try to handle
|
||||
question := r.Question[0].Name
|
||||
|
||||
match := config.NameFilter.FindStringSubmatch(question)
|
||||
|
||||
ip := strings.Replace(match[1], "-", ".", -1)
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
m.Authoritative = true
|
||||
m.RecursionAvailable = true
|
||||
a, err := dns.NewRR(fmt.Sprintf("%s 60 IN A %s", question, ip))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
m.Answer = append(m.Answer, a)
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
} else if len(r.Question) > 0 && config.AliasFilter.MatchString(r.Question[0].Name) {
|
||||
// this is something we know about and we should try to handle
|
||||
question := r.Question[0].Name
|
||||
|
||||
match := config.AliasFilter.FindStringSubmatch(question)
|
||||
|
||||
i := core.InstanceFindByAlias(match[2], match[1])
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
m.Authoritative = true
|
||||
m.RecursionAvailable = true
|
||||
a, err := dns.NewRR(fmt.Sprintf("%s 60 IN A %s", question, i.IP))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
m.Answer = append(m.Answer, a)
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
} else {
|
||||
if len(r.Question) > 0 {
|
||||
question := r.Question[0].Name
|
||||
|
||||
if question == "localhost." {
|
||||
log.Printf("Not a PWD host. Asked for [localhost.] returning automatically [127.0.0.1]\n")
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
m.Authoritative = true
|
||||
m.RecursionAvailable = true
|
||||
a, err := dns.NewRR(fmt.Sprintf("%s 60 IN A 127.0.0.1", question))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
m.Answer = append(m.Answer, a)
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Not a PWD host. Looking up [%s]\n", question)
|
||||
ips, err := net.LookupIP(question)
|
||||
if err != nil {
|
||||
// we have no information about this and we are not a recursive dns server, so we just fail so the client can fallback to the next dns server it has configured
|
||||
w.Close()
|
||||
// dns.HandleFailed(w, r)
|
||||
return
|
||||
}
|
||||
log.Printf("Not a PWD host. Looking up [%s] got [%s]\n", question, ips)
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
m.Authoritative = true
|
||||
m.RecursionAvailable = true
|
||||
for _, ip := range ips {
|
||||
ipv4 := ip.To4()
|
||||
if ipv4 == nil {
|
||||
a, err := dns.NewRR(fmt.Sprintf("%s 60 IN AAAA %s", question, ip.String()))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
m.Answer = append(m.Answer, a)
|
||||
} else {
|
||||
a, err := dns.NewRR(fmt.Sprintf("%s 60 IN A %s", question, ipv4.String()))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
m.Answer = append(m.Answer, a)
|
||||
}
|
||||
}
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
|
||||
} else {
|
||||
log.Printf("Not a PWD host. Got DNS without any question\n")
|
||||
// we have no information about this and we are not a recursive dns server, so we just fail so the client can fallback to the next dns server it has configured
|
||||
w.Close()
|
||||
// dns.HandleFailed(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/play-with-docker/play-with-docker/config"
|
||||
)
|
||||
|
||||
func getTargetInfo(vars map[string]string, req *http.Request) (string, string) {
|
||||
node := vars["node"]
|
||||
port := vars["port"]
|
||||
alias := vars["alias"]
|
||||
sessionPrefix := vars["session"]
|
||||
hostPort := strings.Split(req.Host, ":")
|
||||
|
||||
// give priority to the URL host port
|
||||
if len(hostPort) > 1 && hostPort[1] != config.PortNumber {
|
||||
port = hostPort[1]
|
||||
} else if port == "" {
|
||||
port = "80"
|
||||
}
|
||||
|
||||
if alias != "" {
|
||||
instance := core.InstanceFindByAlias(sessionPrefix, alias)
|
||||
if instance != nil {
|
||||
node = instance.IP
|
||||
return node, port
|
||||
}
|
||||
}
|
||||
|
||||
// Node is actually an ip, need to convert underscores by dots.
|
||||
ip := strings.Replace(node, "-", ".", -1)
|
||||
|
||||
if net.ParseIP(ip) == nil {
|
||||
// Not a valid IP, so treat this is a hostname.
|
||||
} else {
|
||||
node = ip
|
||||
}
|
||||
|
||||
return node, port
|
||||
|
||||
}
|
||||
|
||||
type tcpProxy struct {
|
||||
Director func(*http.Request)
|
||||
ErrorLog *log.Logger
|
||||
Dial func(network, addr string) (net.Conn, error)
|
||||
}
|
||||
|
||||
func (p *tcpProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
logFunc := log.Printf
|
||||
if p.ErrorLog != nil {
|
||||
logFunc = p.ErrorLog.Printf
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
instanceIP := vars["node"]
|
||||
|
||||
if i := core.InstanceFindByIP(strings.Replace(instanceIP, "-", ".", -1)); i == nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
outreq := new(http.Request)
|
||||
// shallow copying
|
||||
*outreq = *r
|
||||
p.Director(outreq)
|
||||
host := outreq.URL.Host
|
||||
|
||||
dial := p.Dial
|
||||
if dial == nil {
|
||||
dial = net.Dial
|
||||
}
|
||||
|
||||
if outreq.URL.Scheme == "wss" || outreq.URL.Scheme == "https" {
|
||||
var tlsConfig *tls.Config
|
||||
tlsConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
dial = func(network, address string) (net.Conn, error) {
|
||||
return tls.Dial("tcp", host, tlsConfig)
|
||||
}
|
||||
}
|
||||
|
||||
d, err := dial("tcp", host)
|
||||
if err != nil {
|
||||
http.Error(w, "Error forwarding request.", 500)
|
||||
logFunc("Error dialing websocket backend %s: %v", outreq.URL, err)
|
||||
return
|
||||
}
|
||||
// All request generated by the http package implement this interface.
|
||||
hj, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
http.Error(w, "Not a hijacker?", 500)
|
||||
return
|
||||
}
|
||||
// Hijack() tells the http package not to do anything else with the connection.
|
||||
// After, it bcomes this functions job to manage it. `nc` is of type *net.Conn.
|
||||
nc, _, err := hj.Hijack()
|
||||
if err != nil {
|
||||
logFunc("Hijack error: %v", err)
|
||||
return
|
||||
}
|
||||
defer nc.Close() // must close the underlying net connection after hijacking
|
||||
defer d.Close()
|
||||
|
||||
// write the modified incoming request to the dialed connection
|
||||
err = outreq.Write(d)
|
||||
if err != nil {
|
||||
logFunc("Error copying request to target: %v", err)
|
||||
return
|
||||
}
|
||||
errc := make(chan error, 2)
|
||||
cp := func(dst io.Writer, src io.Reader) {
|
||||
_, err := io.Copy(dst, src)
|
||||
errc <- err
|
||||
}
|
||||
go cp(d, nc)
|
||||
go cp(nc, d)
|
||||
<-errc
|
||||
}
|
||||
func NewTCPProxy() http.Handler {
|
||||
director := func(req *http.Request) {
|
||||
v := mux.Vars(req)
|
||||
|
||||
node, port := getTargetInfo(v, req)
|
||||
|
||||
if port == "443" {
|
||||
if strings.Contains(req.URL.Scheme, "http") {
|
||||
req.URL.Scheme = "https"
|
||||
} else {
|
||||
req.URL.Scheme = "wss"
|
||||
}
|
||||
}
|
||||
req.URL.Host = fmt.Sprintf("%s:%s", node, port)
|
||||
}
|
||||
return &tcpProxy{Director: director}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
vhost "github.com/inconshreveable/go-vhost"
|
||||
"github.com/play-with-docker/play-with-docker/config"
|
||||
)
|
||||
|
||||
func StartTLSProxy(port string) {
|
||||
|
||||
tlsListener, tlsErr := net.Listen("tcp", fmt.Sprintf(":%s", port))
|
||||
log.Println("Listening on port " + port)
|
||||
if tlsErr != nil {
|
||||
log.Fatal(tlsErr)
|
||||
}
|
||||
defer tlsListener.Close()
|
||||
for {
|
||||
// Wait for TLS Connection
|
||||
conn, err := tlsListener.Accept()
|
||||
if err != nil {
|
||||
log.Printf("Could not accept new TLS connection. Error: %s", err)
|
||||
continue
|
||||
}
|
||||
// Handle connection on a new goroutine and continue accepting other new connections
|
||||
go func(c net.Conn) {
|
||||
defer c.Close()
|
||||
vhostConn, err := vhost.TLS(conn)
|
||||
if err != nil {
|
||||
log.Printf("Incoming TLS connection produced an error. Error: %s", err)
|
||||
return
|
||||
}
|
||||
defer vhostConn.Close()
|
||||
|
||||
var targetIP string
|
||||
targetPort := "443"
|
||||
|
||||
host := vhostConn.ClientHelloMsg.ServerName
|
||||
match := config.NameFilter.FindStringSubmatch(host)
|
||||
if len(match) < 2 {
|
||||
// Not a valid proxy host, try alias hosts
|
||||
match := config.AliasFilter.FindStringSubmatch(host)
|
||||
if len(match) < 4 {
|
||||
// Not valid, just close the connection
|
||||
return
|
||||
} else {
|
||||
alias := match[1]
|
||||
sessionPrefix := match[2]
|
||||
instance := core.InstanceFindByAlias(sessionPrefix, alias)
|
||||
if instance != nil {
|
||||
targetIP = instance.IP
|
||||
} else {
|
||||
return
|
||||
}
|
||||
if len(match) == 4 {
|
||||
targetPort = match[3]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Valid proxy host
|
||||
ip := strings.Replace(match[1], "-", ".", -1)
|
||||
if net.ParseIP(ip) == nil {
|
||||
// Not a valid IP, so treat this is a hostname.
|
||||
return
|
||||
} else {
|
||||
targetIP = ip
|
||||
}
|
||||
if len(match) == 3 {
|
||||
targetPort = match[2]
|
||||
}
|
||||
}
|
||||
|
||||
dest := fmt.Sprintf("%s:%s", targetIP, targetPort)
|
||||
d, err := net.Dial("tcp", dest)
|
||||
if err != nil {
|
||||
log.Printf("Error dialing backend %s: %v\n", dest, err)
|
||||
return
|
||||
}
|
||||
|
||||
errc := make(chan error, 2)
|
||||
cp := func(dst io.Writer, src io.Reader) {
|
||||
_, err := io.Copy(dst, src)
|
||||
errc <- err
|
||||
}
|
||||
go cp(d, vhostConn)
|
||||
go cp(vhostConn, d)
|
||||
<-errc
|
||||
}(conn)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user