Example #1
0
// 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 {}
}
Example #2
0
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)
	}
}