package main import ( "fmt" "net/http" "net/http/httputil" "os" "strings" "time" "github.com/VividCortex/godaemon" "gopkg.in/alecthomas/kingpin.v2" ) var ( routedHostnames map[string]int // Sites are the enabled sites Sites []Site // HTTPClient is the http client HTTPClient http.Client ) var ( logFileLoc = kingpin.Flag("log", "Location of the log file").Default("stdout").String() daemonize = kingpin.Flag("daemon", "If daemonized, the program will run in the background.").Default("false").Bool() sitesLoc = kingpin.Flag("sites_dir", "Location of site files").Short('h').Default("/etc/hostsplitter/").String() bindAddr = kingpin.Flag("bind", "Bind address").Short('b').Default(":80").String() ) func main() { HTTPClient = http.Client{} kingpin.Parse() fmt.Println("Starting hostsplitter") 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) } fmt.Println("Using ", *logFileLoc, " for logging") //log.SetOutput(logFile) } if *daemonize { fmt.Println("Daemonizing... Bye Bye") godaemon.MakeDaemon(&godaemon.DaemonAttr{}) } LoadConfig() go SignalHandler() r := new(revProx) fmt.Println(http.ListenAndServe(*bindAddr, r)) } type revProx struct{} func (p *revProx) ServeHTTP(w http.ResponseWriter, r *http.Request) { if i, ok := routedHostnames[string(r.Host)]; ok { reverseProxy := new(httputil.ReverseProxy) reverseProxy.Director = func(r *http.Request) { r.Header.Set("X-Hostsplitter-Secret", Sites[i].Secret) r.Header.Set("Host", r.Host) r.URL.Scheme = "http" r.URL.Host = Sites[i].GetBackend() r.RequestURI = "" HTTPLogger(r, http.StatusOK) } reverseProxy.ServeHTTP(w, r) } else { HTTPLogger(r, http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Bad Request")) } } const apacheFormatPattern = "%s - - [%s] \"%s %s %s\" %d %d \"%s\" \"%s\" %.4f\n" // 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, )) } }