Committed
This commit is contained in:
parent
0a0abf5698
commit
fdc6c763da
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# binary
|
||||||
|
hostsplitter
|
25
config.go
25
config.go
@ -2,8 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -13,6 +13,7 @@ var (
|
|||||||
config map[string]interface{}
|
config map[string]interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LoadConfig loads the config
|
||||||
func LoadConfig() {
|
func LoadConfig() {
|
||||||
stagedRoutedHostnames := make(map[string]int)
|
stagedRoutedHostnames := make(map[string]int)
|
||||||
stagedSites := []Site{}
|
stagedSites := []Site{}
|
||||||
@ -21,11 +22,11 @@ func LoadConfig() {
|
|||||||
var files []os.FileInfo
|
var files []os.FileInfo
|
||||||
|
|
||||||
if err = os.MkdirAll(*sitesLoc, 0600); err != nil {
|
if err = os.MkdirAll(*sitesLoc, 0600); err != nil {
|
||||||
log.Print(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if files, err = ioutil.ReadDir(*sitesLoc); err != nil {
|
if files, err = ioutil.ReadDir(*sitesLoc); err != nil {
|
||||||
log.Print(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,11 +54,11 @@ func LoadConfig() {
|
|||||||
stagedSites = append(stagedSites, Site{})
|
stagedSites = append(stagedSites, Site{})
|
||||||
|
|
||||||
if dat, err = ioutil.ReadFile(*sitesLoc + "/" + f.Name()); err != nil {
|
if dat, err = ioutil.ReadFile(*sitesLoc + "/" + f.Name()); err != nil {
|
||||||
log.Print(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = json.Unmarshal(dat, &siteConf); err != nil {
|
if err = json.Unmarshal(dat, &siteConf); err != nil {
|
||||||
log.Print(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch siteConf["hostnames"].(type) {
|
switch siteConf["hostnames"].(type) {
|
||||||
@ -65,14 +66,14 @@ func LoadConfig() {
|
|||||||
for _, hostname := range siteConf["hostnames"].([]interface{}) {
|
for _, hostname := range siteConf["hostnames"].([]interface{}) {
|
||||||
switch hostname.(type) {
|
switch hostname.(type) {
|
||||||
case string:
|
case string:
|
||||||
log.Print("Adding hostname -> ", hostname)
|
fmt.Println("Adding hostname -> ", hostname)
|
||||||
stagedRoutedHostnames[hostname.(string)] = siteIndex
|
stagedRoutedHostnames[hostname.(string)] = siteIndex
|
||||||
default:
|
default:
|
||||||
log.Print("Expected string but got ", reflect.TypeOf(hostname), " while parsing hostname in ", f.Name())
|
fmt.Println("Expected string but got ", reflect.TypeOf(hostname), " while parsing hostname in ", f.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Print("Expected array but got ", reflect.TypeOf(siteConf["hostnames"]), " while parsing hosts in ", f.Name())
|
fmt.Println("Expected array but got ", reflect.TypeOf(siteConf["hostnames"]), " while parsing hosts in ", f.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch siteConf["backends"].(type) {
|
switch siteConf["backends"].(type) {
|
||||||
@ -80,21 +81,21 @@ func LoadConfig() {
|
|||||||
for _, backend := range siteConf["backends"].([]interface{}) {
|
for _, backend := range siteConf["backends"].([]interface{}) {
|
||||||
switch backend.(type) {
|
switch backend.(type) {
|
||||||
case string:
|
case string:
|
||||||
log.Print("Adding backend -> ", backend)
|
fmt.Println("Adding backend -> ", backend)
|
||||||
stagedSites[siteIndex].Backends = append(stagedSites[siteIndex].Backends, backend.(string))
|
stagedSites[siteIndex].Backends = append(stagedSites[siteIndex].Backends, backend.(string))
|
||||||
default:
|
default:
|
||||||
log.Print("Expected string but got ", reflect.TypeOf(backend), " while parsing backend in ", f.Name())
|
fmt.Println("Expected string but got ", reflect.TypeOf(backend), " while parsing backend in ", f.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Print("Expected array but got ", reflect.TypeOf(siteConf["backends"]), " while parsing backends in ", f.Name())
|
fmt.Println("Expected array but got ", reflect.TypeOf(siteConf["backends"]), " while parsing backends in ", f.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch siteConf["secret"].(type) {
|
switch siteConf["secret"].(type) {
|
||||||
case string:
|
case string:
|
||||||
stagedSites[siteIndex].Secret = siteConf["secret"].(string)
|
stagedSites[siteIndex].Secret = siteConf["secret"].(string)
|
||||||
default:
|
default:
|
||||||
log.Print("Expected string but got ", reflect.TypeOf(siteConf["secret"]), " while parsing secret in ", f.Name())
|
fmt.Println("Expected string but got ", reflect.TypeOf(siteConf["secret"]), " while parsing secret in ", f.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
routedHostnames = stagedRoutedHostnames
|
routedHostnames = stagedRoutedHostnames
|
||||||
|
@ -2,10 +2,11 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/VividCortex/godaemon"
|
"github.com/VividCortex/godaemon"
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
@ -13,7 +14,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
routedHostnames map[string]int
|
routedHostnames map[string]int
|
||||||
|
// Sites are the enabled sites
|
||||||
Sites []Site
|
Sites []Site
|
||||||
|
// HTTPClient is the http client
|
||||||
HTTPClient http.Client
|
HTTPClient http.Client
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,20 +32,20 @@ func main() {
|
|||||||
|
|
||||||
kingpin.Parse()
|
kingpin.Parse()
|
||||||
|
|
||||||
log.Print("Starting hostsplitter")
|
fmt.Println("Starting hostsplitter")
|
||||||
|
|
||||||
if *logFileLoc != "stdout" {
|
if *logFileLoc != "stdout" {
|
||||||
logFile, err := os.OpenFile(*logFileLoc, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640)
|
logFile, err := os.OpenFile(*logFileLoc, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640)
|
||||||
defer logFile.Close()
|
defer logFile.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error opening file: %v", err)
|
fmt.Println("error opening file: %v", err)
|
||||||
}
|
}
|
||||||
log.Print("Using ", *logFileLoc, " for logging")
|
fmt.Println("Using ", *logFileLoc, " for logging")
|
||||||
log.SetOutput(logFile)
|
//log.SetOutput(logFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *daemonize {
|
if *daemonize {
|
||||||
log.Print("Daemonizing... Bye Bye")
|
fmt.Println("Daemonizing... Bye Bye")
|
||||||
godaemon.MakeDaemon(&godaemon.DaemonAttr{})
|
godaemon.MakeDaemon(&godaemon.DaemonAttr{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,22 +53,78 @@ func main() {
|
|||||||
|
|
||||||
go SignalHandler()
|
go SignalHandler()
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(*bindAddr, &httputil.ReverseProxy{
|
fmt.Println(http.ListenAndServe(*bindAddr, &httputil.ReverseProxy{
|
||||||
Director: func(r *http.Request) {
|
Director: func(r *http.Request) {
|
||||||
HTTPLogger(r)
|
|
||||||
if i, ok := routedHostnames[string(r.Host)]; ok {
|
if i, ok := routedHostnames[string(r.Host)]; ok {
|
||||||
r.Header.Set("X-Hostsplitter-Secret", Sites[i].Secret)
|
r.Header.Set("X-Hostsplitter-Secret", Sites[i].Secret)
|
||||||
r.Header.Set("Host", r.Host)
|
r.Header.Set("Host", r.Host)
|
||||||
r.URL.Scheme = "http"
|
r.URL.Scheme = "http"
|
||||||
r.URL.Host = Sites[i].GetBackend()
|
r.URL.Host = Sites[i].GetBackend()
|
||||||
r.RequestURI = ""
|
r.RequestURI = ""
|
||||||
|
HTTPLogger(r, http.StatusOK)
|
||||||
} else {
|
} else {
|
||||||
log.Print("%q is not routed", r.Host)
|
r.URL.Host = ""
|
||||||
|
r.URL.Scheme = ""
|
||||||
|
HTTPLogger(r, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func HTTPLogger(r *http.Request) {
|
const apacheFormatPattern = "%s - - [%s] \"%s %s %s\" %d %d \"%s\" \"%s\" %.4f\n"
|
||||||
log.Print(fmt.Sprintf("httplog> %v %v (%v) (conlen %v)", r.Host, r.Method, r.RequestURI, r.RemoteAddr))
|
|
||||||
|
// HTTPLogger logs an http request
|
||||||
|
func HTTPLogger(r *http.Request, status int) {
|
||||||
|
if *logFileLoc != "stdout" {
|
||||||
|
logFile, err := os.OpenFile(*logFileLoc, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640)
|
||||||
|
defer logFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error opening file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
timeFormatted := time.Now().Format("02/Jan/2006 03:04:05")
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
|
||||||
|
clientIP = clientIP[:colon]
|
||||||
|
}
|
||||||
|
|
||||||
|
referer := r.Referer()
|
||||||
|
if referer == "" {
|
||||||
|
referer = "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
userAgent := r.UserAgent()
|
||||||
|
if userAgent == "" {
|
||||||
|
userAgent = "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(logFile, fmt.Sprintf(
|
||||||
|
apacheFormatPattern,
|
||||||
|
clientIP,
|
||||||
|
timeFormatted,
|
||||||
|
r.Method,
|
||||||
|
r.RequestURI,
|
||||||
|
r.Proto,
|
||||||
|
status,
|
||||||
|
0,
|
||||||
|
referer,
|
||||||
|
userAgent,
|
||||||
|
0.00,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
record := &ApacheLogRecord{
|
||||||
|
ResponseWriter: rw,
|
||||||
|
ip: clientIP,
|
||||||
|
time: time.Time{},
|
||||||
|
method: r.Method,
|
||||||
|
uri: r.RequestURI,
|
||||||
|
protocol: r.Proto,
|
||||||
|
status: http.StatusOK,
|
||||||
|
referer: referer,
|
||||||
|
userAgent: userAgent,
|
||||||
|
elapsedTime: time.Duration(0),
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SignalHandler handles a config reload on a pkill 10
|
||||||
func SignalHandler() {
|
func SignalHandler() {
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.Signal(0xa))
|
signal.Notify(sigs, syscall.Signal(0xa))
|
||||||
for {
|
for {
|
||||||
if <-sigs == syscall.Signal(0xa) {
|
if <-sigs == syscall.Signal(0xa) {
|
||||||
log.Print("Recieved 0xa, reloading config")
|
fmt.Println("Recieved 0xa, reloading config")
|
||||||
LoadConfig()
|
LoadConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user