package main import ( "encoding/json" "fmt" "github.com/gorilla/mux" log "github.com/sirupsen/logrus" "net" "net/http" ) type HttpServer struct { _server *http.Server _database *Database _oauth *OAuth2 _renderer *Renderer _dnsclient *DnsUpdate _ipAddresses map[string][]string } type GuiSetting struct { FilterString *string } func getIP(r *http.Request) (string, error) { var host string forwarded := r.Header.Get("X-FORWARDED-FOR") if forwarded != "" { host = forwarded } else { host = r.RemoteAddr } host,_ , err := net.SplitHostPort(host) if err != nil { return "", err } return host, nil } func (h *HttpServer) doaction(w http.ResponseWriter, r *http.Request, params *AdminPageParams){ if action := r.URL.Query().Get("action"); action != "" { switch action { case "update": host := r.URL.Query().Get("host") ip := r.URL.Query().Get("ip") if !h._database.ExistHost(host) { params.Alerts = append(params.Alerts, Alert{Type:"error", Message: fmt.Sprintf("host %s does not exist", host)}) break } err := h._dnsclient.Update(host, ip) if err != nil { params.Alerts = append(params.Alerts, Alert{Type:"error", Message: err.Error()}) } else { params.Alerts = append(params.Alerts, Alert{Type:"success", Message: "successfully updated host"}) } break case "delete": host := r.URL.Query().Get("host") log.Info("deleting host " + host) h._database.DeleteHost(host) h._dnsclient.Remove(host) delete(h._ipAddresses, host) break case "externalresolve": host := r.URL.Query().Get("host") ips, err := h._dnsclient.ExternalResolve(host) if err != nil { params.Alerts = append(params.Alerts, Alert{ Type: "error", Message: fmt.Sprintf("host %s could not be resolved", host), }) } else { params.Alerts = append(params.Alerts, Alert{ Type: "success", Message: fmt.Sprintf("host %s resolved to following addresses:\n %s", host, fmt.Sprint(ips)), }) } case "resolve": host := r.URL.Query().Get("host") ipAddresses, err := h._dnsclient.Resolve(host) if err == nil && len(ipAddresses) > 0 { params.Alerts = append(params.Alerts, Alert{ Type: "success", Message: fmt.Sprintf("host %s resolved to following addresses:\n %s", host, fmt.Sprint(ipAddresses)), }) h._ipAddresses[host] = ipAddresses } else { params.Alerts = append(params.Alerts, Alert{ Type: "error", Message: fmt.Sprintf("host %s could not be resolved", host), }) delete(h._ipAddresses, host) } case "add": host := r.URL.Query().Get("host") _, err := h._database.CreateHost(host) if err == nil { params.Alerts = append(params.Alerts, Alert{ Type: "success", Message: fmt.Sprintf("created host %s", host), }) } else { params.Alerts = append(params.Alerts, Alert{ Type: "error", Message: fmt.Sprintf("could not create host %s.\n reason: %s", host, err.Error()), }) } break } } else { } } func (h *HttpServer) doguisetting(w http.ResponseWriter, r *http.Request) *GuiSetting{ settings := new(GuiSetting) settings.FilterString = nil if setting := r.URL.Query().Get("setting"); setting != "" { switch setting { case "filter": host := r.URL.Query().Get("host") settings.FilterString = &host break } } return settings } func (h *HttpServer) adminPage(w http.ResponseWriter, r *http.Request) { token, ok := h._oauth.checkOAuth(w, r, true) if !ok { return } params := new(AdminPageParams) params.Alerts = make([]Alert, 0) params.Hosts = make(map[string]string) params.IpAddresses = h._ipAddresses h.doaction(w,r, params) settings := h.doguisetting(w,r) claims, _ := h._oauth.GetClaims(w, token) params.Email = claims.Email params.Profile = claims.Profile if settings.FilterString != nil { params.Hosts = h._database.GetExistingHosts(*settings.FilterString) params.Alerts = append( params.Alerts, Alert{ Type: "info", Message: fmt.Sprintf("returned %d hosts", len(params.Hosts)), }) } else { params.Hosts = h._database.GetExistingHosts("") } h._renderer.RenderAdminPage(w, params) } func (h *HttpServer) registerHandler(w http.ResponseWriter, r *http.Request) { if _, ok := h._oauth.checkOAuth(w, r, false); ok { return } host := r.URL.Query().Get("host") clientip, err := getIP(r) if err != nil { log.Fatal(err) } if h._database.IsBannedHost(clientip) { h._database.IncrementBanHost(clientip) log.Error("host ", clientip, " is banned!") w.WriteHeader(http.StatusForbidden) return } if h._database.ExistHost(host) { h._database.IncrementBanHost(clientip) w.WriteHeader(http.StatusNotAcceptable) return } token, err := h._database.CreateHost(host) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } ret := map[string]string { "host": host, "token": token, } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(ret) } func (h *HttpServer) updateHandler(w http.ResponseWriter, r *http.Request) { hosts := r.URL.Query()["host"] tokens := r.URL.Query()["token"] myips := r.URL.Query()["myip"] var myip string clientip, err := getIP(r) if h._database.IsBannedHost(clientip) { h._database.IncrementBanHost(clientip) log.Error("host ", clientip, " is banned!") w.WriteHeader(http.StatusForbidden) return } if err != nil { log.Fatal(err) } if len(hosts) == 0 { h._database.IncrementBanHost(clientip) w.WriteHeader(http.StatusNotAcceptable) return } if len(tokens) == 0 { h._database.IncrementBanHost(clientip) w.WriteHeader(http.StatusNotAcceptable) return } if len(myips) == 0 { myip = clientip if err != nil { w.WriteHeader(http.StatusInternalServerError) return } } else { myip = myips[0] } host := hosts[0] token := tokens[0] if !h._database.Authorize(host, token) { h._database.IncrementBanHost(clientip) w.WriteHeader(http.StatusForbidden) return } log.Info("authorization successful.") log.Info("will update host ", host, " ip ", myip) w.WriteHeader(http.StatusOK) } func (h *HttpServer) Listen() { h._server.ListenAndServe() } func CreateHttpServer(config *Config) *HttpServer { var httpserver *HttpServer var err error httpserver = new(HttpServer) r := mux.NewRouter() httpserver._ipAddresses = make(map[string][]string) httpserver._renderer, err = CreateRenderer(config) if err != nil { log.Fatal(err) } httpserver._database, err = CreateDatabase(config) if err != nil { log.Fatal(err) } httpserver._oauth, err = CreateOAuth2(config) if err != nil { log.Fatal(err) } httpserver._dnsclient = NewTestInstance() httpserver._server = &http.Server{ Addr: config.Addr, Handler: r, } r.HandleFunc("/register", httpserver.registerHandler) r.HandleFunc("/update", httpserver.updateHandler) r.HandleFunc("/admin", httpserver.adminPage) return httpserver }