Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
GDNSD-PLUGIN-GEOIP(8)		      gdnsd		   GDNSD-PLUGIN-GEOIP(8)

NAME
     gdnsd-plugin-geoip - gdnsd meta-plugin for GSLB + failover via MaxMind's
     GeoIP2 databases

SYNOPSIS
     Minimal example gdnsd config file using this plugin:

       plugins => { geoip => {
	 maps => {
	   my_prod_map => {
	     geoip2_db => GeoIP2-City.mmdb,
	     datacenters => [dc-03, dc-02, dc-01, dc-fail],
	     map => {
		 EU => {
		     DE => [dc-03, dc-01, dc-fail],
		     CH => [dc-01, dc-03, dc-fail]
		 },
		 NA => { MX => [dc-02, dc-fail] }
	     }
	   },
	   my_auto_map => {
	     geoip2_db => GeoIP2-Country.mmdb,
	     datacenters => [dc1, dc2],
	     auto_dc_coords => {
		dc1 => [ 38.9, -77 ],
		dc2 => [ 50.1, 8.7 ],
	     }
	   }
	 },
	 resources => {
	   prod_www => {
	     map => my_prod_map
	     service_types => up
	     dcmap => {
	       dc-01 => 192.0.2.1,
	       dc-02 => { lb01 => 192.0.2.2, lb02 => 192.0.2.3 },
	       dc-03 => [ 192.0.2.4, 192.0.2.5, 192.0.2.6 ],
	       dc-fail => last.resort.cname.example.net.
	     }
	   }
	   corp_www => {
	     map => my_auto_map
	     dcmap => {
	       dc1 => 192.0.2.100,
	       dc2 => 192.0.2.101
	     }
	   }
	 }
       }}

     Example zonefile RRs in zone example.com:

       www	600 DYNA geoip!prod_www
       www-dc01 600 DYNA geoip!prod_www/dc-01
       www.corp 600 DYNA geoip!corp_www

DESCRIPTION
     gdnsd-plugin-geoip uses MaxMind's GeoIP2 binary databases to map address
     and CNAME results based on geography and monitored service availability.
     It fully supports both IPv6 and the emerging edns-client-subnet standard.
     If a request contains the edns-client-subnet option with a source netmask
     greater than zero, the edns-client-subnet information will be used instead
     of the source IP of the request (the IP of the querying cache).

     It supports the GeoIP2 format databases, which typically end in .mmdb.  It
     does not supports the legacy GeoIP1 format databases (which typically end
     in .dat).

     It can also be used with no GeoIP database at all, in which case the only
     network-mapping input comes from the "nets" config data or an external
     "nets" file, which explicitly map subnets to datacenter lists.

     This plugin can operate in an automatic distance-based mode (using a
     City-level database's coordinate information) It can also operate coordi-
     nate-free and rely on the user to configure a hierarchical map of cascading
     default user-location-to-datacenter mappings, starting at the continent
     level.

     The two modes can also be effectively mixed at geographic boundaries.

     For each "map" you define (which maps geographic location codes to prefer-
     ence-ordered lists of your datacenter locations), this plugin merges all of
     the raw GeoIP subnets into the largest possible supernets which contain
     identical responses in your configuration.  These in turn are used to set
     larger edns-client-subnet scope masks than you'd see simply returning raw
     GeoIP results.

PLUGIN_METAFO
     The documentation for gdnsd-plugin-metafo(8) is required reading for under-
     standing the geoip plugin documentation here.  The geoip plugin is an exact
     superset of the metafo plugin, and re-uses almost all of the metafo plu-
     gin's source code.  Metafo does failover along a single, global, ordered
     list of datacenters.  What plugin_geoip adds on top of the functionality of
     metafo is the ability to have the order of the datacenter failover list be-
     come dynamic per-request based on geographic hints derived from the
     client's network address.

FILE LOCATIONS
     The configuration of this plugin can reference several external configura-
     tion and/or data files.  By default, all files referenced in this plugin's
     configuration are loaded from the geoip subdirectory of the daemon's con-
     figuration directory (default /usr/local/etc/gdnsd).  You can load from
     other locations by specifying absolute file paths.

CONFIGURATION - TOP-LEVEL
     The top level of the geoip plugin's configuration (i.e. "plugins => { geoip
     => { ... } }") supports only three explicit keys.	One is the optional set-
     ting "undefined_datacenters_ok".

     The other two are required and expanded upon in detail in the next two sec-
     tions: "maps", and "resources".  The "maps" section defines one or more
     named mappings of location information from GeoIP binary databases to or-
     dered subsets of datacenter names.  The "resources" section defines one or
     more named resources, each of which references one of the named maps and
     resolves datacenter names to specific sets of addresses or CNAMEs.

     Any other keys present at this level will be inherited down inside of each
     per-resource hash inside the "resources" stanza, acting as per-resource de-
     faults for anything not defined explicitly there.

   "undefined_datacenters_ok = false"
     Boolean, default false.  If set to true, geoip resources are allowed to
     leave some of the datacenters specified in their "map" undefined in their
     resource-level "dcmap".  For example, a map M might define 3 datacenters
     named A, B, and C, but a resource using map M might only define result ad-
     dresses for datacenters B and C in its "dcmap".  This would otherwise be a
     hard configuration error.

     !!! DANGER !!! - Setting this value to true is a good way to shoot yourself
     in the foot if you're not very careful about how your maps and resources
     are configured with respect to each other, especially in "City Auto Mode".
     Maps are calculated without any knowledge of the resources that use them.
     If a specific network or location maps to a list of datacenters which con-
     tains none of the defined datacenters for a given resource, the results of
     runtime queries for that resource from that location or network will be the
     empty set (no answer records at all).  This is virtually guaranteed to hap-
     pen in "City Auto Mode" if the number of undefined datacenters in a re-
     source is greater than or equal to the map's "auto_dc_limit".

CONFIGURATION - MAPS
     All "maps"-level configuration keys are the names of the maps you choose to
     define.  A map, conceptually, is a mapping between geography and/or network
     topology to varying ordered datacenter sub-sets.  The value of each named
     map must be a hash, and the following configuration keys apply within:

   "geoip2_db = GeoIP2-City.mmdb"
     String, filename, optional.  This is the filename of a MaxMind GeoIP2 for-
     mat database.  It should contain either the City or Country data model.
     There is no distinction made here for the IP version, and it is normal for
     these databases to contain both IPv4 and IPv6 data together.  If one or the
     other is missing, clients using that address family will be defaulted.

   "datacenters = [ one, two, three, ... ]"
     Array of strings, required.  This is the total set of datacenter names used
     by this map.  You must define at least one datacenter name (although 2 or
     more would be infinitely more useful).  At this time, there is a maximum
     limit of 254 datacenter names per map, although this could be raised if
     anyone requires it.  The order specified here is the fallback default re-
     sult ordering in various default cases (e.g. if no explicit top-level map
     default list is given).

   "ignore_ecs = true"
     Boolean, default false.  If this is set to "true", all resources using this
     map will ignore EDNS Client Subnet (ECS) information when performing
     lookups against the map, relying solely on the DNS source IP for the
     lookup.  If the client provided ECS in such a query, the response will also
     contain the ECS option to signal that we're ECS aware in general, but the
     response scope mask will be set to zero to signal the cache that the ECS
     data wasn't used and the result is globally cacheable.

     This is useful for situations in which the map is intentionally meant to
     operate solely on recursor IPs rather than ECS IPs, but other maps serviced
     by the same authserver do make use of ECS data, and thus the global
     edns_client_subnet config option can't be used to disable handling the op-
     tion completely for the whole server.

   "nets = { ... }"
     Key-value hash, optional (see below for alternate form).  If specified, the
     contents should be key-value pairs of "network/netmask" mapped to a data-
     center name (or an array of datacenter names).  Any network-to-datacenter
     mappings specified here will override mappings determined via GeoIP.  Note
     that it is illegal to specify networks in the IPv4-like subspaces of IPv6
     other than v4compat, but it is legal to specify actual IPv4 networks (which
     are treated identically to v4compat).  See the section on IPv4 Compatible
     Addresses later in this document for more details.  The order of the net-
     works is unimportant; they will always be sorted and inserted such that an
     entry which is a subnet of another entry is not obliterated by the parent
     supernet.

	 nets => {
	     10.0.0.0/8 => [ dc1, dc2 ],
	     192.0.2.128/25 => dc3
	     2001:DB8::/32 => [ dc4, dc5, dc6 ],
	 }

     In the case that one entry is a subnet of another with a different result
     dclist, the entries are merged correctly such that the supernet surrounds
     the subnet.  In the case of an exact duplicate entry (or an effective one,
     after merging smaller subnets) with a different dclist, it is arbitrary
     which one "wins" and the condition is warned about.  If you care about this
     case, you should sanitize your nets data beforehand with an external tool
     and/or parse for the warning message in log outputs.

   "nets = nets_file_name"
     String pathname, optional.  A variant of the above, but the contents of the
     key-value hash are loaded from the named external file.  This makes life
     easier for external tools and scripts generating large sets of nets entries
     (e.g. from BGP data).  The file will be monitored for changes and reloaded
     at runtime much like the GeoIP databases.

   "map = { ... }"
     Key-value hash, optional.	This is the heart of a named map which uses
     GeoIP: the map itself, which maps places to ordered lists of datacenters.
     It requires "geoip2_db" is also specified, and makes no sense without it.

     This is a nested key-value hash.  At each level, the keys are location
     codes (continent, country, region/subdivision, or city information depend-
     ing on depth), and the values are either an ordered datacenter array (e.g.
     "[ dc03, dc01, dc04 ]"), or a sub-hash containing a deeper level of dis-
     tinction.	At each layer, a special key named "default" is available, which
     sets the default for everything within the current scope.	The top-level
     default itself defaults to the ordered list from "datacenters" in the nor-
     mal case.	If the entire "map" stanza is missing or empty, you just get the
     default behavior of "default".  A datacenter array can also be empty, which
     implies that this location is mapped to receive no response data (the
     server will still respond to the query, and will not issue an NXDOMAIN.  It
     will simply be a NODATA/NOERROR response like you'd get if there were no
     records of this type, but could be records of other types for the same
     name).

   GeoIP2 Location Data Hierarchy
     The top level of the map hierarchy is comprised of MaxMind's seven conti-
     nent codes: "AF" for Africa, "AS" for Asia, "NA" for North America, "SA"
     for South America, "EU" for Europe, "OC" for Oceania, and "AN" for Antarc-
     tica.  The next level is the ISO 3166-1 2-letter country code.

     From here there are a number of Subdivision levels, the count of which
     varies for different network database entries.  In the US, for example,
     there is only one level of subdivision data for the US States.  In the
     Czech Republic there are two levels of subdivision: first into 14 regions,
     and then further into 91 districts.  Subdivisions are all specified using
     their ISO 3166-2 codes directly.

     After all subdivision levels, the final level is the City level.  The City
     names are all in the UTF-8 character set.	Currently this plugin only uses
     the English city names from the database, even though other languages may
     be available depending on the database.

     As a pragmatic answer to the issues that can arise with multiple subdivi-
     sion layers, the map automatically searches deeper in the database data
     when no map match is found at a given level of the map hierarchy beneath
     the Country level.  This means you can skip over any levels of Subdivision
     detail in your map that are irrelevant to you.

     For example, this targets the New Zealand regional council subdivision of
     Otago without explicitly specifying the enclosing subdivision for the South
     Island:

       { OC => { NZ => { OTA => [...] } } }

     As another example, this works correctly for targeting the city of Paris
     without caring about what layers of subdivisions lie between it and FR:

       { EU => { FR => { Paris => [...] } } }

CONFIGURATION - MAPS - CITY AUTO MODE
     "City-auto-mode" is a special mode of operation that automatically maps out
     the world to your datacenters based on coordinate math, so that you don't
     have to manually construct a complex hierarchical "map".  It can still be
     mixed with "map" of course, allowing you to use auto-mode for only select
     geographic areas if you wish (or disabling it for select areas by specify-
     ing manual lists).  The key parameter is "auto_dc_coords", which enables
     city-auto-mode.  This requires a City-level GeoIP2 database; the Country
     ones don't contain coordinate information.

     "auto_dc_coords = { ... }"
	 Key-value hash, optional.  If this option is specified, the whole map's
	 basic mode of operation changes to "city-auto-mode".  The contents of
	 the hash are a key for each datacenter named in "datacenters", with
	 their values set to an array of "[lat, lon]" in decimal degree units.
	 When city-auto-mode is enabled by this, the following configura-
	 tion-validation changes occur from the default, static-mapping mode:
	 the loaded GeoIP2 database(s) are required be City-level databases, and
	 the special keyword "auto" becomes a legal "datacenter list" in the
	 "map" stanza.

	 With city-auto-mode enabled, the top-level map "default" defaults to
	 "auto", but can be overridden with a manual list.  For any location
	 that maps to "auto", the coordinates specified here in "auto_dc_coords"
	 will be compared with the coordinates from the City-level database(s)
	 to determine an automatic distance-sorted datacenter list.

	 If you omit one or more defined datacenters from the coordinate list in
	 "auto_dc_coords", those datacenters will not be used in automatic re-
	 sults, but will still be available for manual use via "map" and/or
	 "nets" entries.

     "auto_dc_limit = N"
	 Unsigned integer, optional, default 3.  When city-auto-mode is in ef-
	 fect, this is the upper length limit for auto-generated lists.  3 is a
	 reasonable default even if you have a considerably longer set of data-
	 centers, as this provides a primary as well as two fallbacks.	Raising
	 this to a large number in the presence of a long datacenter list will
	 cause the set of unique result datacenter lists to increase rapidly,
	 and thus reduce the optimization of the final result database for
	 edns-client-subnet purposes.  It's really not worth raising this value
	 in almost any case, unless you really need to handle more than 3 random
	 datacenters going offline at the same time and still have clients fail
	 elsewhere.  The value zero is treated as unlimited (highly un-recom-
	 mended).

     Under city-auto-mode, when the top-level default is (explicitly or implic-
     itly) "auto", there is still a fallback static ordering which is the whole
     ordered "datacenters" list, which is the normal static default "default"
     when not in city-auto-mode.  This fallback is used when no location infor-
     mation is available at all (e.g. IPv6 client vs IPv4 GeoIP DB, Anonymous
     Proxies, etc).

MAP TESTING
     A binary program "gdnsd_geoip_test" is included.  This can be used directly
     from the commandline, parses the relevant bits of your gdnsd config file
     for geoip map info, and then provides datacenter list results for IP ad-
     dress + map combinations supplied by the user.  Useful for debugging your
     maps and testing the mapping of client IPs.  It has a separate manpage
     gdnsd_geoip_test(1).

CONFIGURATION - RESOURCES
     Resource-level configuration within the "resources" stanza is nearly iden-
     tical to the resources configuration of the metafo plugin, with all of the
     same basic behaviors about synthesizing or directly referencing the config-
     uration of other plugins per-datacenter.

     One difference is that metafo's per-resource "datacenters" array is re-
     placed with "map => mapname", which references one of the maps defined in
     the "maps" stanza, described in detail earlier.  The set of defined data-
     centers in the "dcmap" stanza must match the total set of datacenters de-
     fined by the referenced map, unless "undefined_datacenters_ok" is set to
     "true" (see warnings and documentation above).

     The "skip_first" flag can also be set per resource, and is much more useful
     with the geoip plugin than it is with the basic metafo plugin.  If this
     flag is set, the first datacenter in the failover list for a given lookup
     will be skipped, allowing the definition of a "second choice" resource us-
     ing the same basic map definition as the first choice.  In this case the
     original first choice is *never* a possible answer, and the rest of the
     logic (e.g. skipping datacenters marked as down) proceeds as normal with
     the remaining list.  If the map entry and/or the resource definition have
     already reduced the effective datacenter count to one, the flag has no ef-
     fect.

META-PLUGIN INTERACTION
     Both of the meta-plugins ("metafo" and "geoip") can reference their own as
     well as each others' resources by direct reference within a "dcmap", so
     long as a resource does not directly refer to itself.  This allows plu-
     gin-layering configurations such as geoip -> metafo -> weighted, or metafo
     -> geoip -> multifo, or even metafo -> metafo -> simplefo, etc.

     Bear in mind that once you begin using inter-meta-plugin references, you
     could create a reference loop.  gdnsd does not currently detect or prevent
     such loops, and they will cause complete runtime failure when queried,
     probably by running out of stack space during recursion.

     Additionally, "geoip" can synthesize configuration for "metafo" resources,
     but the reverse does not hold; "metafo" cannot synthesize configuration for
     "geoip" resources.

IPv4 Compatible Addresses
     This plugin knows of six different relatively-trivial ways to map IPv4 ad-
     dresses into the IPv6 address space.  These are shown below in as much de-
     tail matters to this plugin, with "NNNN:NNNN" in place of the copied IPv4
     address bytes:

	      ::0000:NNNN:NNNN/96   # RFC 4291 - v4compat (deprecated)
	      ::ffff:NNNN:NNNN/96   # RFC 4291 - v4mapped
	 ::ffff:0000:NNNN:NNNN/96   # RFC 2765 - SIIT (obsoleted)
	    64:ff9b::NNNN:NNNN/96   # RFC 6052 - Well-Known Prefix
	 2001:0000:X:NNNN:NNNN/32   # RFC 4380 - Teredo (IPv4 bits are flipped)
		2002:NNNN:NNNN::/16 # RFC 3056 - 6to4

	 (in the Teredo case above, "X" represents some variable non-zero bytes
	  that occupy the center 64 bits of the address).

     All of this plugin's internal lookup databases are IPv6 databases, and any
     IPv4-like information is always stored in the v4compat space within these
     databases.  When doing runtime lookups all other v4-like addresses (raw
     IPv4 addresses, v4mapped, SIIT, WKP, Teredo, and 6to4) are converted to the
     canonical v4compat IPv6 representation before querying the internal data-
     bases.  The other representations (v4mapped, SIIT, WKP, Teredo, 6to4) are
     Undefined internally, and will never be referenced at lookup-time due to
     the v4compat conversion mentioned earlier.

     The "nets" stanza is not allowed to specify entries in the five undefined
     v4-like IPv6 spaces (those other than v4compat).  Specify those networks as
     normal IPv4 networks or v4compat networks instead.  Legitimate IPv6 "nets"
     entries which happen to be a supernet of any v4-like spaces will *not* un-
     duly affect v4-like lookups.  There is no functional difference between
     v4compat and native v4 forms in "nets", e.g. "192.0.2.0/24" and
     "::C000:0200/120" are completely identical.

     GeoIP databases that are natively IPv4-only get all of their data loaded
     into the v4compat space only.  For normal IPv6 GeoIP databases, by default
     we load the v4compat space directly (which is where MaxMind stores IPv4
     data in their IPv6 databases), but ignore the v4mapped/SIIT/Teredo/6to4
     spaces (some of which are empty in MaxMind's databases, and some of which
     simply alias the v4compat space).

ANOTHER CONFIG EXAMPLE
     A relatively-maximal example config, showing the interaction of valid
     "maps" and "resources" sections:

       service_types => {
	 xmpp_svc => { plugin => "tcp_connect", ... }
	 www_svc => { plugin => "http_status", ... }
       }
       plugins => {
	 geoip => {
	   maps => {
	     my_prod_map => {
	       geoip2_db => GeoIP2-City.mmdb,
	       datacenters => [us-01, de-01, sg-01],
	       map => {
		   # Hierarchy is Continent -> Country -> Region -> City
		   NA => {
		     US => {
		       Dallas => [sg-01],
		     }
		   }
		   SA => [us-01, sg-01, de-01],
		   EU => {
		     default => [de-01, us-01, sg-01],
		     CH => {
		       Geneve => {
			 Geneva => [sg-01],
		       }
		     }
		   }
		   AF => [de-01, us-01, sg-01],
		   AS => [sg-01, de-01, us-01],
		   OC => [sg-01, us-01, de-01],
	       }
	       nets => {
		   10.0.0.0/8 => [ de-01 ],
		   2001:DB8::/32 => [ us-01 ],
	       }
	     }
	     my_auto_map => {
	       geoip2_db => GeoIP2-City.mmdb,
	       datacenters => [us-01, de-01, sg-01],
	       auto_dc_coords => {
		  us-01 => [ 38.9, -77 ],
		  de-01 => [ 50.1, 8.7 ],
		  sg-01 => [ 1.3, 103.9 ],
	       }
	     }
	   }
	   resources => {
	     prod_app => {
	       map => my_auto_map
	       # these two are inherited multifo config keys
	       #  for all of the dcmap below:
	       service_types => [www_svc, xmpp_svc],
	       up_thresh => 0.4,
	       dcmap => {
		 us-01 => {
		   lb01 => 192.0.2.1,
		   lb02 => 192.0.2.2,
		   lb03 => 192.0.2.3,
		   lb01.v6 => 2001:DB8::1,
		   lb02.v6 => 2001:DB8::2,
		   lb03.v6 => 2001:DB8::3,
		 },
		 sg-01 => {
		   lb01 => 192.0.2.4,
		   lb02 => 192.0.2.5,
		   lb03 => 192.0.2.6,
		   lb01.v6 => 2001:DB8::4,
		   lb02.v6 => 2001:DB8::5,
		   lb03.v6 => 2001:DB8::6,
		 },
		 de-01 => {
		   lb01 => 192.0.2.7,
		   lb02 => 192.0.2.8,
		   lb03 => 192.0.2.9,
		   lb01.v6 => 2001:DB8::7,
		   lb02.v6 => 2001:DB8::8,
		   lb03.v6 => 2001:DB8::9,
		 },
	       }
	     },
	     prod_cdn => {
	       map => my_prod_map,
	       dcmap => {
		 us-01 => us-cdn-provider.example.net.
		 sg-01 => asia-cdn-provider.example.net.
		 de-01 => europe-cdn-provider.example.net.
	       }
	     }
	   }
	 }
       }

     Example zonefile RRs in zone example.com:

       app     600 DYNA geoip!prod_app
       app.us  600 DYNA geoip!prod_app/us-01
       app.sg  600 DYNA geoip!prod_app/sg-01
       app.de  600 DYNA geoip!prod_app/de-01
       content 600 DYNC geoip!prod_cdn

EXAMPLE OF METAFO->GEOIP CITY-AUTO-MODE w/ LAST RESORT CNAME
       plugins => {
	 geoip => {
	   maps => {
	     auto_map => {
	       geoip2_db => GeoIP2-City.mmdb,
	       datacenters => [dc1, dc2, dc3, dc4],
	       auto_dc_coords => {
		  dc1 => [ 38.9, -77 ],
		  dc2 => [ 50.1, 8.7 ],
		  dc3 => [ 20.2, 88.9 ],
		  dc4 => [ 39.0, -20 ],
	       },
	       # only fail through the nearest 2 before giving up:
	       auto_dc_limit => 2,
	     }
	   },
	   resources => {
	     www_real => {
	       map => my_auto_map,
	       service_types => [ http, xmpp ],
	       dcmap => {
		 dc1 => 192.0.2.100,
		 dc2 => 192.0.2.101,
		 dc3 => 192.0.2.102,
		 dc4 => 192.0.2.103
	       }
	     }
	   }
	 },
	 metafo => {
	   resources => {
	     www => {
	       datacenters => [ real, backup ],
	       dcmap => {
		 real => %geoip!www_real,
		 backup => backup-host.example.net.
	       }
	     }
	   }
	 }
       }

       And in the example.com zonefile:

       ; This tries through the closest 2/4 datacenters to
       ;   the client from the geoip map, and if both of
       ;   those are down it returns a CNAME to backup-host.example.net.
       ;   for a downtime message or something:
       www DYNC metafo!www

SEE ALSO
     gdnsd-plugin-metafo(8), gdnsd_geoip_test(1), gdnsd.config(5), gdnsd.zone-
     file(5), gdnsd(8)

     The gdnsd manual.

COPYRIGHT AND LICENSE
     Copyright (c) 2012 Brandon L Black <blblack@gmail.com>

     This file is part of gdnsd.

     gdnsd is free software: you can redistribute it and/or modify it under the
     terms of the GNU General Public License as published by the Free Software
     Foundation, either version 3 of the License, or (at your option) any later
     version.

     gdnsd is distributed in the hope that it will be useful, but WITHOUT ANY
     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     FOR A PARTICULAR PURPOSE.	See the GNU General Public License for more de-
     tails.

     You should have received a copy of the GNU General Public License along
     with gdnsd.  If not, see <http://www.gnu.org/licenses/>.

gdnsd 3.8.0			   2026-08-01		   GDNSD-PLUGIN-GEOIP(8)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=gdnsd-plugin-geoip&sektion=8&manpath=FreeBSD+Ports+15.1.quarterly>

home | help