// Run is the entrypoint for the freegeoip daemon tool. func Run() error { flag.Parse() if *flVersion { fmt.Printf("freegeoip v%s\n", Version) return nil } if *flLogToStdout { log.SetOutput(os.Stdout) } log.SetPrefix("[freegeoip] ") addrs := strings.Split(*flRedisAddr, ",") rc, err := redis.NewClient(addrs...) if err != nil { return err } rc.SetTimeout(*flRedisTimeout) db, err := openDB(*flDB, *flUpdateIntvl, *flRetryIntvl) if err != nil { return err } go watchEvents(db) ah := NewHandler(&HandlerConfig{ Prefix: *flAPIPrefix, Origin: *flCORSOrigin, PublicDir: *flPublicDir, DB: db, RateLimiter: RateLimiter{ Redis: rc, Max: *flQuotaMax, Interval: *flQuotaIntvl, }, }) if !*flSilent { ah = gorilla.CombinedLoggingHandler(os.Stderr, ah) } if *flUseXFF { ah = freegeoip.ProxyHandler(ah) } if len(*flInternalServer) > 0 { http.Handle("/metrics", prometheus.Handler()) log.Println("freegeoip internal server starting on", *flInternalServer) go func() { log.Fatal(http.ListenAndServe(*flInternalServer, nil)) }() } if *flHTTPAddr != "" { log.Println("freegeoip http server starting on", *flHTTPAddr) srv := &http.Server{ Addr: *flHTTPAddr, Handler: ah, ReadTimeout: *flReadTimeout, WriteTimeout: *flWriteTimeout, ConnState: ConnStateMetrics(httpConnsGauge), } go func() { log.Fatal(srv.ListenAndServe()) }() } if *flHTTPSAddr != "" { log.Println("freegeoip https server starting on", *flHTTPSAddr) srv := &http.Server{ Addr: *flHTTPSAddr, Handler: ah, ReadTimeout: *flReadTimeout, WriteTimeout: *flWriteTimeout, ConnState: ConnStateMetrics(httpsConnsGauge), } http2.ConfigureServer(srv, nil) go func() { log.Fatal(srv.ListenAndServeTLS(*flCertFile, *flKeyFile)) }() } select {} }
func main() { addr := flag.String("addr", ":8080", "Address in form of ip:port to listen on") certFile := flag.String("cert", "", "X.509 certificate file") keyFile := flag.String("key", "", "X.509 key file") public := flag.String("public", "", "Public directory to serve at the / endpoint") ipdb := flag.String("db", maxmindFile, "IP database file or URL") updateIntvl := flag.Duration("update", 24*time.Hour, "Database update check interval") retryIntvl := flag.Duration("retry", time.Hour, "Max time to wait before retrying update") useXFF := flag.Bool("use-x-forwarded-for", false, "Use the X-Forwarded-For header when available") silent := flag.Bool("silent", false, "Do not log requests to stderr") redisAddr := flag.String("redis", "127.0.0.1:6379", "Redis address in form of ip:port for quota") redisTimeout := flag.Duration("redis-timeout", 500*time.Millisecond, "Redis read/write timeout") quotaMax := flag.Int("quota-max", 0, "Max requests per source IP per interval; Set 0 to turn off") quotaIntvl := flag.Duration("quota-interval", time.Hour, "Quota expiration interval") version := flag.Bool("version", false, "Show version and exit") pprof := flag.String("pprof", "", "Address in form of ip:port to listen on for pprof") flag.Parse() if *version { fmt.Printf("freegeoip v%s\n", Version) return } rc, err := redis.Dial(*redisAddr) if err != nil { log.Fatal(err) } rc.Timeout = *redisTimeout db, err := openDB(*ipdb, *updateIntvl, *retryIntvl) if err != nil { log.Fatal(err) } runtime.GOMAXPROCS(runtime.NumCPU()) encoders := map[string]http.Handler{ "/csv/": freegeoip.NewHandler(db, &freegeoip.CSVEncoder{UseCRLF: true}), "/xml/": freegeoip.NewHandler(db, &freegeoip.XMLEncoder{Indent: true}), "/json/": freegeoip.NewHandler(db, &freegeoip.JSONEncoder{}), } if *quotaMax > 0 { seconds := int((*quotaIntvl).Seconds()) for path, f := range encoders { encoders[path] = userQuota(rc, *quotaMax, seconds, f, *silent) } } mux := http.NewServeMux() for path, handler := range encoders { mux.Handle(path, handler) } if len(*public) > 0 { mux.Handle("/", http.FileServer(http.Dir(*public))) } handler := CORS(mux, "GET", "HEAD") if !*silent { log.Println("freegeoip server starting on", *addr) go logEvents(db) handler = logHandler(handler) } if *useXFF { handler = freegeoip.ProxyHandler(handler) } if len(*pprof) > 0 { go func() { log.Fatal(http.ListenAndServe(*pprof, nil)) }() } if len(*certFile) > 0 && len(*keyFile) > 0 { err = http.ListenAndServeTLS(*addr, *certFile, *keyFile, handler) } else { err = http.ListenAndServe(*addr, handler) } if err != nil { log.Fatal(err) } }