Ejemplo n.º 1
0
// HTTPServer is the constructor of the HTTP server
func HTTPServer(redis *database.Redis, cache *mirrors.Cache) *HTTP {
	h := new(HTTP)
	h.redis = redis
	h.geoip = network.NewGeoIP()
	h.templates.mirrorlist = template.Must(h.LoadTemplates("mirrorlist"))
	h.templates.mirrorstats = template.Must(h.LoadTemplates("mirrorstats"))
	h.templates.downloadstats = template.Must(h.LoadTemplates("downloadstats"))
	h.templates.useragentstats = template.Must(h.LoadTemplates("useragentstats"))
	h.cache = cache
	h.stats = NewStats(redis)
	h.engine = DefaultEngine{}
	h.blockedUAs = GetConfig().UserAgentStatsConf.BlockedUserAgents
	h.uACountOnlyS = GetConfig().UserAgentStatsConf.CountOnlySpecialPath
	h.uACountSpecial = GetConfig().UserAgentStatsConf.CountSpecialPath
	h.parseUA = h.uACountOnlyS == false || len(h.blockedUAs) > 0
	http.Handle("/", NewGzipHandler(h.requestDispatcher))

	// Load the GeoIP databases
	if err := h.geoip.LoadGeoIP(); err != nil {
		if gerr, ok := err.(network.GeoIPError); ok {
			for _, e := range gerr.Errors {
				log.Critical(e.Error())
			}
			if gerr.IsFatal() {
				if len(GetConfig().Fallbacks) == 0 {
					log.Fatal("Can't load the GeoIP databases, please set a valid path in the mirrorbits configuration")
				} else {
					log.Critical("Can't load the GeoIP databases, all requests will be served by the fallback mirrors")
				}
			} else {
				log.Critical("One or more GeoIP database could not be loaded, service will run in degraded mode")
			}
		}
	}

	// Initialize the random number generator
	rand.Seed(time.Now().UnixNano())
	return h
}
Ejemplo n.º 2
0
func (c *cli) CmdAdd(args ...string) error {
	cmd := SubCmd("add", "[OPTIONS] IDENTIFIER", "Add a new mirror")
	http := cmd.String("http", "", "HTTP base URL")
	rsync := cmd.String("rsync", "", "RSYNC base URL (for scanning only)")
	ftp := cmd.String("ftp", "", "FTP base URL (for scanning only)")
	sponsorName := cmd.String("sponsor-name", "", "Name of the sponsor")
	sponsorURL := cmd.String("sponsor-url", "", "URL of the sponsor")
	sponsorLogo := cmd.String("sponsor-logo", "", "URL of a logo to display for this mirror")
	adminName := cmd.String("admin-name", "", "Admin's name")
	adminEmail := cmd.String("admin-email", "", "Admin's email")
	customData := cmd.String("custom-data", "", "Associated data to return when the mirror is selected (i.e. json document)")
	continentOnly := cmd.Bool("continent-only", false, "The mirror should only handle its continent")
	countryOnly := cmd.Bool("country-only", false, "The mirror should only handle its country")
	asOnly := cmd.Bool("as-only", false, "The mirror should only handle clients in the same AS number")
	score := cmd.Int("score", 0, "Weight to give to the mirror during selection")
	comment := cmd.String("comment", "", "Comment")

	if err := cmd.Parse(args); err != nil {
		return nil
	}
	if cmd.NArg() < 1 {
		cmd.Usage()
		return nil
	}

	if strings.Contains(cmd.Arg(0), " ") {
		fmt.Fprintf(os.Stderr, "The identifier cannot contain a space\n")
		os.Exit(-1)
	}

	if *http == "" {
		fmt.Fprintf(os.Stderr, "You *must* pass at least an HTTP URL\n")
		os.Exit(-1)
	}

	if !strings.HasPrefix(*http, "http://") && !strings.HasPrefix(*http, "https://") {
		*http = "http://" + *http
	}

	u, err := url.Parse(*http)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Can't parse HTTP url\n")
		os.Exit(-1)
	}

	ip, err := network.LookupMirrorIP(u.Host)
	if err == network.ErrMultipleAddresses {
		fmt.Fprintf(os.Stderr, "Warning: the hostname returned more than one address! This is highly unreliable.\n")
	} else if err != nil {
		log.Fatal("IP lookup failed: ", err.Error())
	}

	geo := network.NewGeoIP()
	if err := geo.LoadGeoIP(); err != nil {
		log.Fatal(err.Error())
	}

	geoRec := geo.GetRecord(ip)

	r := database.NewRedis()
	conn, err := r.Connect()
	if err != nil {
		log.Fatal("Redis: ", err)
	}
	defer conn.Close()

	key := fmt.Sprintf("MIRROR_%s", cmd.Arg(0))
	exists, err := redis.Bool(conn.Do("EXISTS", key))
	if err != nil {
		return err
	}
	if exists {
		fmt.Fprintf(os.Stderr, "Mirror %s already exists!\n", cmd.Arg(0))
		os.Exit(-1)
	}

	// Normalize the URLs
	if http != nil {
		*http = utils.NormalizeURL(*http)
	}
	if rsync != nil {
		*rsync = utils.NormalizeURL(*rsync)
	}
	if ftp != nil {
		*ftp = utils.NormalizeURL(*ftp)
	}

	var latitude, longitude float32
	var continentCode, countryCode string

	if geoRec.GeoIPRecord != nil {
		latitude = geoRec.GeoIPRecord.Latitude
		longitude = geoRec.GeoIPRecord.Longitude
		continentCode = geoRec.GeoIPRecord.ContinentCode
		countryCode = geoRec.GeoIPRecord.CountryCode
	} else {
		fmt.Fprintf(os.Stderr, "Warning: unable to guess the geographic location of %s\n", cmd.Arg(0))
	}

	_, err = conn.Do("HMSET", key,
		"ID", cmd.Arg(0),
		"http", *http,
		"rsync", *rsync,
		"ftp", *ftp,
		"sponsorName", *sponsorName,
		"sponsorURL", *sponsorURL,
		"sponsorLogo", *sponsorLogo,
		"adminName", *adminName,
		"adminEmail", *adminEmail,
		"customData", *customData,
		"continentOnly", *continentOnly,
		"countryOnly", *countryOnly,
		"asOnly", *asOnly,
		"score", *score,
		"latitude", fmt.Sprintf("%f", latitude),
		"longitude", fmt.Sprintf("%f", longitude),
		"continentCode", continentCode,
		"countryCodes", countryCode,
		"asnum", geoRec.ASNum,
		"comment", strings.TrimSpace(*comment),
		"enabled", false,
		"up", false)
	if err != nil {
		goto oops
	}

	_, err = conn.Do("LPUSH", "MIRRORS", cmd.Arg(0))
	if err != nil {
		goto oops
	}

	// Publish update
	database.Publish(conn, database.MIRROR_UPDATE, cmd.Arg(0))

	fmt.Println("Mirror added successfully")
	return nil
oops:
	fmt.Fprintf(os.Stderr, "Oops: %s", err)
	os.Exit(-1)
	return nil
}