<?xml version='1.0' encoding='utf-8'?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" version="3" category="info" docName="draft-google-self-published-geofeeds-09" indexInclude="true" ipr="trust200902" number="8805" prepTime="2020-08-06T16:24:16" scripts="Common,Latin" sortRefs="true" submissionType="independent" symRefs="true" tocDepth="4" tocInclude="true" xml:lang="en">
  <link href="https://datatracker.ietf.org/doc/draft-google-self-published-geofeeds-09" rel="prev"/>
  <link href="https://dx.doi.org/10.17487/rfc8805" rel="alternate"/>
  <link href="urn:issn:2070-1721" rel="alternate"/>
  <front>
    <title abbrev="Self-Published IP Geofeeds">A Format for Self-Published IP Geolocation Feeds</title>
    <seriesInfo name="RFC" value="8805" stream="independent"/>
    <author fullname="Erik Kline" initials="E." surname="Kline">
      <organization showOnFrontPage="true">Loon LLC</organization>
      <address>
        <postal>
          <street>1600 Amphitheatre Parkway</street>
          <city>Mountain View</city>
          <region>CA</region>
          <code>94043</code>
          <country>United States of America</country>
        </postal>
        <email>ek@loon.com</email>
      </address>
    </author>
    <author fullname="Krzysztof Duleba" initials="K." surname="Duleba">
      <organization showOnFrontPage="true">Google</organization>
      <address>
        <postal>
          <street>1600 Amphitheatre Parkway</street>
          <city>Mountain View</city>
          <region>CA</region>
          <code>94043</code>
          <country>United States of America</country>
        </postal>
        <email>kduleba@google.com</email>
      </address>
    </author>
    <author fullname="Zoltan Szamonek" initials="Z." surname="Szamonek">
      <organization showOnFrontPage="true">Google Switzerland GmbH</organization>
      <address>
        <postal>
          <street>Brandschenkestrasse 110</street>
          <code>8002</code>
          <city>Zürich</city>
          <country>Switzerland</country>
        </postal>
        <email>zszami@google.com</email>
      </address>
    </author>
    <author fullname="Stefan Moser" initials="S." surname="Moser">
      <organization showOnFrontPage="true">Google Switzerland GmbH</organization>
      <address>
        <postal>
          <street>Brandschenkestrasse 110</street>
          <code>8002</code>
          <city>Zürich</city>
          <country>Switzerland</country>
        </postal>
        <email>smoser@google.com</email>
      </address>
    </author>
    <author fullname="Warren Kumari" initials="W." surname="Kumari">
      <organization showOnFrontPage="true">Google</organization>
      <address>
        <postal>
          <street>1600 Amphitheatre Parkway</street>
          <city>Mountain View</city>
          <region>CA</region>
          <code>94043</code>
          <country>United States of America</country>
        </postal>
        <email>warren@kumari.net</email>
      </address>
    </author>
    <date month="08" year="2020"/>
    <abstract pn="section-abstract">
      <t pn="section-abstract-1">This document records a format whereby a network operator can publish
      a mapping of IP address prefixes to simplified geolocation information,
      colloquially termed a "geolocation feed".  Interested parties can poll
      and parse these feeds to update or merge with other geolocation data
      sources and procedures.  This format intentionally only allows specifying
      coarse-level location.</t>
      <t pn="section-abstract-2">Some technical organizations operating networks that move from one
      conference location to the next have already experimentally published
      small geolocation feeds.</t>
      <t pn="section-abstract-3">This document describes a currently deployed format. At
      least one consumer (Google) has incorporated these feeds into a
      geolocation data pipeline, and a significant number of ISPs are
      using it to inform them where their prefixes should be geolocated.</t>
    </abstract>
    <boilerplate>
      <section anchor="status-of-memo" numbered="false" removeInRFC="false" toc="exclude" pn="section-boilerplate.1">
        <name slugifiedName="name-status-of-this-memo">Status of This Memo</name>
        <t pn="section-boilerplate.1-1">
            This document is not an Internet Standards Track specification; it is
            published for informational purposes.
        </t>
        <t pn="section-boilerplate.1-2">
            This is a contribution to the RFC Series, independently of any
            other RFC stream.  The RFC Editor has chosen to publish this
            document at its discretion and makes no statement about its value
            for implementation or deployment.  Documents approved for
            publication by the RFC Editor are not candidates for any level of
            Internet Standard; see Section 2 of RFC 7841.
        </t>
        <t pn="section-boilerplate.1-3">
            Information about the current status of this document, any
            errata, and how to provide feedback on it may be obtained at
            <eref target="https://www.rfc-editor.org/info/rfc8805" brackets="none"/>.
        </t>
      </section>
      <section anchor="copyright" numbered="false" removeInRFC="false" toc="exclude" pn="section-boilerplate.2">
        <name slugifiedName="name-copyright-notice">Copyright Notice</name>
        <t pn="section-boilerplate.2-1">
            Copyright (c) 2020 IETF Trust and the persons identified as the
            document authors. All rights reserved.
        </t>
        <t pn="section-boilerplate.2-2">
            This document is subject to BCP 78 and the IETF Trust's Legal
            Provisions Relating to IETF Documents
            (<eref target="https://trustee.ietf.org/license-info" brackets="none"/>) in effect on the date of
            publication of this document. Please review these documents
            carefully, as they describe your rights and restrictions with
            respect to this document.
        </t>
      </section>
    </boilerplate>
    <toc>
      <section anchor="toc" numbered="false" removeInRFC="false" toc="exclude" pn="section-toc.1">
        <name slugifiedName="name-table-of-contents">Table of Contents</name>
        <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1">
          <li pn="section-toc.1-1.1">
            <t pn="section-toc.1-1.1.1"><xref derivedContent="1" format="counter" sectionFormat="of" target="section-1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-introduction">Introduction</xref></t>
            <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.1.2">
              <li pn="section-toc.1-1.1.2.1">
                <t keepWithNext="true" pn="section-toc.1-1.1.2.1.1"><xref derivedContent="1.1" format="counter" sectionFormat="of" target="section-1.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-motivation">Motivation</xref></t>
              </li>
              <li pn="section-toc.1-1.1.2.2">
                <t keepWithNext="true" pn="section-toc.1-1.1.2.2.1"><xref derivedContent="1.2" format="counter" sectionFormat="of" target="section-1.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-requirements-notation">Requirements Notation</xref></t>
              </li>
              <li pn="section-toc.1-1.1.2.3">
                <t keepWithNext="true" pn="section-toc.1-1.1.2.3.1"><xref derivedContent="1.3" format="counter" sectionFormat="of" target="section-1.3"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-assumptions-about-publicati">Assumptions about Publication</xref></t>
              </li>
            </ul>
          </li>
          <li pn="section-toc.1-1.2">
            <t pn="section-toc.1-1.2.1"><xref derivedContent="2" format="counter" sectionFormat="of" target="section-2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-self-published-ip-geolocati">Self-Published IP Geolocation Feeds</xref></t>
            <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.2.2">
              <li pn="section-toc.1-1.2.2.1">
                <t pn="section-toc.1-1.2.2.1.1"><xref derivedContent="2.1" format="counter" sectionFormat="of" target="section-2.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-specification">Specification</xref></t>
                <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.2.2.1.2">
                  <li pn="section-toc.1-1.2.2.1.2.1">
                    <t pn="section-toc.1-1.2.2.1.2.1.1"><xref derivedContent="2.1.1" format="counter" sectionFormat="of" target="section-2.1.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-geolocation-feed-individual">Geolocation Feed Individual Entry Fields</xref></t>
                    <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.2.2.1.2.1.2">
                      <li pn="section-toc.1-1.2.2.1.2.1.2.1">
                        <t pn="section-toc.1-1.2.2.1.2.1.2.1.1"><xref derivedContent="2.1.1.1" format="counter" sectionFormat="of" target="section-2.1.1.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-ip-prefix">IP Prefix</xref></t>
                      </li>
                      <li pn="section-toc.1-1.2.2.1.2.1.2.2">
                        <t pn="section-toc.1-1.2.2.1.2.1.2.2.1"><xref derivedContent="2.1.1.2" format="counter" sectionFormat="of" target="section-2.1.1.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-alpha2code-previously-count">Alpha2code (Previously: 'country')</xref></t>
                      </li>
                      <li pn="section-toc.1-1.2.2.1.2.1.2.3">
                        <t pn="section-toc.1-1.2.2.1.2.1.2.3.1"><xref derivedContent="2.1.1.3" format="counter" sectionFormat="of" target="section-2.1.1.3"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-region">Region</xref></t>
                      </li>
                      <li pn="section-toc.1-1.2.2.1.2.1.2.4">
                        <t pn="section-toc.1-1.2.2.1.2.1.2.4.1"><xref derivedContent="2.1.1.4" format="counter" sectionFormat="of" target="section-2.1.1.4"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-city">City</xref></t>
                      </li>
                      <li pn="section-toc.1-1.2.2.1.2.1.2.5">
                        <t pn="section-toc.1-1.2.2.1.2.1.2.5.1"><xref derivedContent="2.1.1.5" format="counter" sectionFormat="of" target="section-2.1.1.5"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-postal-code">Postal Code</xref></t>
                      </li>
                    </ul>
                  </li>
                  <li pn="section-toc.1-1.2.2.1.2.2">
                    <t pn="section-toc.1-1.2.2.1.2.2.1"><xref derivedContent="2.1.2" format="counter" sectionFormat="of" target="section-2.1.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-prefixes-with-no-geolocatio">Prefixes with No Geolocation Information</xref></t>
                  </li>
                  <li pn="section-toc.1-1.2.2.1.2.3">
                    <t pn="section-toc.1-1.2.2.1.2.3.1"><xref derivedContent="2.1.3" format="counter" sectionFormat="of" target="section-2.1.3"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-additional-parsing-requirem">Additional Parsing Requirements</xref></t>
                  </li>
                </ul>
              </li>
              <li pn="section-toc.1-1.2.2.2">
                <t pn="section-toc.1-1.2.2.2.1"><xref derivedContent="2.2" format="counter" sectionFormat="of" target="section-2.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-examples">Examples</xref></t>
              </li>
            </ul>
          </li>
          <li pn="section-toc.1-1.3">
            <t pn="section-toc.1-1.3.1"><xref derivedContent="3" format="counter" sectionFormat="of" target="section-3"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-consuming-self-published-ip">Consuming Self-Published IP Geolocation Feeds</xref></t>
            <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.3.2">
              <li pn="section-toc.1-1.3.2.1">
                <t pn="section-toc.1-1.3.2.1.1"><xref derivedContent="3.1" format="counter" sectionFormat="of" target="section-3.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-feed-integrity">Feed Integrity</xref></t>
              </li>
              <li pn="section-toc.1-1.3.2.2">
                <t pn="section-toc.1-1.3.2.2.1"><xref derivedContent="3.2" format="counter" sectionFormat="of" target="section-3.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-verification-of-authority">Verification of Authority</xref></t>
              </li>
              <li pn="section-toc.1-1.3.2.3">
                <t pn="section-toc.1-1.3.2.3.1"><xref derivedContent="3.3" format="counter" sectionFormat="of" target="section-3.3"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-verification-of-accuracy">Verification of Accuracy</xref></t>
              </li>
              <li pn="section-toc.1-1.3.2.4">
                <t pn="section-toc.1-1.3.2.4.1"><xref derivedContent="3.4" format="counter" sectionFormat="of" target="section-3.4"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-refreshing-feed-information">Refreshing Feed Information</xref></t>
              </li>
            </ul>
          </li>
          <li pn="section-toc.1-1.4">
            <t pn="section-toc.1-1.4.1"><xref derivedContent="4" format="counter" sectionFormat="of" target="section-4"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-privacy-considerations">Privacy Considerations</xref></t>
          </li>
          <li pn="section-toc.1-1.5">
            <t pn="section-toc.1-1.5.1"><xref derivedContent="5" format="counter" sectionFormat="of" target="section-5"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-relation-to-other-work">Relation to Other Work</xref></t>
          </li>
          <li pn="section-toc.1-1.6">
            <t pn="section-toc.1-1.6.1"><xref derivedContent="6" format="counter" sectionFormat="of" target="section-6"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-security-considerations">Security Considerations</xref></t>
          </li>
          <li pn="section-toc.1-1.7">
            <t pn="section-toc.1-1.7.1"><xref derivedContent="7" format="counter" sectionFormat="of" target="section-7"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-planned-future-work">Planned Future Work</xref></t>
          </li>
          <li pn="section-toc.1-1.8">
            <t pn="section-toc.1-1.8.1"><xref derivedContent="8" format="counter" sectionFormat="of" target="section-8"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-finding-self-published-ip-g">Finding Self-Published IP Geolocation Feeds</xref></t>
            <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.8.2">
              <li pn="section-toc.1-1.8.2.1">
                <t pn="section-toc.1-1.8.2.1.1"><xref derivedContent="8.1" format="counter" sectionFormat="of" target="section-8.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-ad-hoc-well-known-uris">Ad Hoc 'Well-Known' URIs</xref></t>
              </li>
              <li pn="section-toc.1-1.8.2.2">
                <t pn="section-toc.1-1.8.2.2.1"><xref derivedContent="8.2" format="counter" sectionFormat="of" target="section-8.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-other-mechanisms">Other Mechanisms</xref></t>
              </li>
            </ul>
          </li>
          <li pn="section-toc.1-1.9">
            <t pn="section-toc.1-1.9.1"><xref derivedContent="9" format="counter" sectionFormat="of" target="section-9"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-iana-considerations">IANA Considerations</xref></t>
          </li>
          <li pn="section-toc.1-1.10">
            <t pn="section-toc.1-1.10.1"><xref derivedContent="10" format="counter" sectionFormat="of" target="section-10"/>. <xref derivedContent="" format="title" sectionFormat="of" target="name-references">References</xref></t>
            <ul bare="true" empty="true" indent="2" spacing="compact" pn="section-toc.1-1.10.2">
              <li pn="section-toc.1-1.10.2.1">
                <t pn="section-toc.1-1.10.2.1.1"><xref derivedContent="10.1" format="counter" sectionFormat="of" target="section-10.1"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-normative-references">Normative References</xref></t>
              </li>
              <li pn="section-toc.1-1.10.2.2">
                <t pn="section-toc.1-1.10.2.2.1"><xref derivedContent="10.2" format="counter" sectionFormat="of" target="section-10.2"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-informative-references">Informative References</xref></t>
              </li>
            </ul>
          </li>
          <li pn="section-toc.1-1.11">
            <t pn="section-toc.1-1.11.1"><xref derivedContent="Appendix A" format="default" sectionFormat="of" target="section-appendix.a"/>.  <xref derivedContent="" format="title" sectionFormat="of" target="name-sample-python-validation-co">Sample Python Validation Code</xref></t>
          </li>
          <li pn="section-toc.1-1.12">
            <t pn="section-toc.1-1.12.1"><xref derivedContent="" format="none" sectionFormat="of" target="section-appendix.b"/><xref derivedContent="" format="title" sectionFormat="of" target="name-acknowledgements">Acknowledgements</xref></t>
          </li>
          <li pn="section-toc.1-1.13">
            <t pn="section-toc.1-1.13.1"><xref derivedContent="" format="none" sectionFormat="of" target="section-appendix.c"/><xref derivedContent="" format="title" sectionFormat="of" target="name-authors-addresses">Authors' Addresses</xref></t>
          </li>
        </ul>
      </section>
    </toc>
  </front>
  <middle>
    <section numbered="true" toc="include" removeInRFC="false" pn="section-1">
      <name slugifiedName="name-introduction">Introduction</name>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-1.1">
        <name slugifiedName="name-motivation">Motivation</name>
        <t pn="section-1.1-1">Providers of services over the Internet have grown to depend on
        best-effort geolocation information to improve the user experience.
        Locality information can aid in directing traffic to the nearest
        serving location, inferring likely native language, and providing
        additional context for services involving search queries.</t>
        <t pn="section-1.1-2">When an ISP, for example, changes the location where an IP prefix
        is deployed, services that make use of geolocation information may
        begin to suffer degraded performance. This can lead to customer
        complaints, possibly to the ISP directly. Dissemination of correct
        geolocation data is complicated by the lack of any centralized means
        to coordinate and communicate geolocation information to all
        interested consumers of the data.</t>
        <t pn="section-1.1-3">This document records a format whereby a network operator (an ISP,
        an enterprise, or any organization that deems the geolocation of its
        IP prefixes to be of concern) can publish a mapping of IP address
        prefixes to simplified geolocation information, colloquially termed a
        "geolocation feed". Interested parties can poll and parse these feeds
        to update or merge with other geolocation data sources and
        procedures.</t>
        <t pn="section-1.1-4">This document describes a currently deployed format. At
        least one consumer (Google) has incorporated these feeds into a
        geolocation data pipeline, and a significant number of ISPs are
        using it to inform them where their prefixes should be geolocated.</t>
      </section>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-1.2">
        <name slugifiedName="name-requirements-notation">Requirements Notation</name>
        <t pn="section-1.2-1">
    The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
    "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>",
    "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>", 
    "<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are
    to be interpreted as 
    described in BCP 14 <xref target="RFC2119" format="default" sectionFormat="of" derivedContent="RFC2119"/> <xref target="RFC8174" format="default" sectionFormat="of" derivedContent="RFC8174"/> 
    when, and only when, they appear in all capitals, as shown here.
        </t>
        <t pn="section-1.2-2">As this is an informational document about a data format and set of
        operational practices presently in use, requirements notation captures
        the design goals of the authors and implementors.</t>
      </section>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-1.3">
        <name slugifiedName="name-assumptions-about-publicati">Assumptions about Publication</name>
        <t pn="section-1.3-1">This document describes both a format and a mechanism for
        publishing data, with the assumption that the network operator to whom
        operational responsibility has been delegated for any published data
        wishes it to be public. Any privacy risk is bounded by the format, and
        feed publishers <bcp14>MAY</bcp14> omit prefixes or any location field associated with
        a given prefix to further protect privacy (see <xref target="spec" format="default" sectionFormat="of" derivedContent="Section 2.1"/>
        for details about which fields exactly may be omitted). Feed publishers
        assume the responsibility of determining which data should be made
        public.</t>
        <t pn="section-1.3-2">This document does not incorporate a mechanism to communicate
        acceptable use policies for self-published data. Publication itself is
        inferred as a desire by the publisher for the data to be usefully
        consumed, similar to the publication of information like host names,
        cryptographic keys, and Sender Policy Framework (SPF) records <xref target="RFC7208" format="default" sectionFormat="of" derivedContent="RFC7208"/> in the DNS.</t>
      </section>
    </section>
    <section numbered="true" toc="include" removeInRFC="false" pn="section-2">
      <name slugifiedName="name-self-published-ip-geolocati">Self-Published IP Geolocation Feeds</name>
      <t pn="section-2-1">The format described here was developed to address the need of
      network operators to rapidly and usefully share geolocation information
      changes. Originally, there arose a specific case where regional
      operators found it desirable to publish location changes rather than
      wait for geolocation algorithms to "learn" about them. Later, technical
      conferences that frequently use the same network prefixes advertised
      from different conference locations experimented by publishing
      geolocation feeds updated in advance of network location changes in
      order to better serve conference attendees.</t>
      <t pn="section-2-2">At its simplest, the mechanism consists of a network operator
      publishing a file (the "geolocation feed") that contains several text
      entries, one per line. Each entry is keyed by a unique (within the feed)
      IP prefix (or single IP address) followed by a sequence of network
      locality attributes to be ascribed to the given prefix.</t>
      <section anchor="spec" numbered="true" toc="include" removeInRFC="false" pn="section-2.1">
        <name slugifiedName="name-specification">Specification</name>
        <t pn="section-2.1-1">For operational simplicity, every feed should contain data about
        all IP addresses the provider wants to publish. Alternatives, like
        publishing only entries for IP addresses whose geolocation data has
        changed or differ from current observed geolocation behavior "at
        large", are likely to be too operationally complex.</t>
        <t pn="section-2.1-2">Feeds <bcp14>MUST</bcp14> use UTF-8 <xref target="RFC3629" format="default" sectionFormat="of" derivedContent="RFC3629"/> character encoding. 
        Lines are delimited by a line break (CRLF) (as specified in
        <xref target="RFC4180" format="default" sectionFormat="of" derivedContent="RFC4180"/>), and blank lines are ignored.
        Text from a '#' character to the end of the current line is treated
        as a comment only and is similarly ignored (note that this does not
        strictly follow <xref target="RFC4180" format="default" sectionFormat="of" derivedContent="RFC4180"/>, which has no
	support for comments).</t>
        <t pn="section-2.1-3">Feed lines that are not comments <bcp14>MUST</bcp14> be formatted
	as comma-separated values (CSV), as described in <xref target="RFC4180" format="default" sectionFormat="of" derivedContent="RFC4180"/>. Each feed entry is a text line of
	the form:</t>
        <artwork name="" type="" align="left" alt="" pn="section-2.1-4">
ip_prefix,alpha2code,region,city,postal_code
</artwork>
        <t pn="section-2.1-5">The IP prefix field is <bcp14>REQUIRED</bcp14>, all others are
	<bcp14>OPTIONAL</bcp14> (can be empty), though the requisite minimum
	number of commas <bcp14>SHOULD</bcp14> be present.</t>
        <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.1">
          <name slugifiedName="name-geolocation-feed-individual">Geolocation Feed Individual Entry Fields</name>
          <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.1.1">
            <name slugifiedName="name-ip-prefix">IP Prefix</name>
            <t pn="section-2.1.1.1-1"><bcp14>REQUIRED</bcp14>: Each IP prefix field
	    <bcp14>MUST</bcp14> be either a single IP address or an IP prefix
	    in Classless Inter-Domain Routing (CIDR) notation in conformance
	    with <xref target="RFC4632" sectionFormat="of" section="3.1" format="default" derivedLink="https://rfc-editor.org/rfc/rfc4632#section-3.1" derivedContent="RFC4632"/> for
	    IPv4 or <xref target="RFC4291" sectionFormat="of" section="2.3" format="default" derivedLink="https://rfc-editor.org/rfc/rfc4291#section-2.3" derivedContent="RFC4291"/>
	    for IPv6.</t>
            <t pn="section-2.1.1.1-2">Examples include "192.0.2.1" and "192.0.2.0/24" for IPv4 and
            "2001:db8::1" and "2001:db8::/32" for IPv6.</t>
          </section>
          <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.1.2">
            <name slugifiedName="name-alpha2code-previously-count">Alpha2code (Previously: 'country')</name>
            <t pn="section-2.1.1.2-1"><bcp14>OPTIONAL</bcp14>: The alpha2code field, if non-empty,
	    <bcp14>MUST</bcp14> be a 2-letter 
            ISO country code conforming to ISO 3166-1 alpha 2 <xref target="ISO.3166.1alpha2" format="default" sectionFormat="of" derivedContent="ISO.3166.1alpha2"/>. Parsers
	    <bcp14>SHOULD</bcp14> treat this field 
            case-insensitively.</t>
            <t pn="section-2.1.1.2-2">Earlier versions of this document called this field "country",
	    and it may still be referred to as such in existing
	    tools/interfaces.</t>
            <t pn="section-2.1.1.2-3">Parsers <bcp14>MAY</bcp14> additionally support other 2-letter
	    codes outside the ISO 3166-1 alpha 2 codes, such as the 2-letter
	    codes from the "Exceptionally reserved codes" <xref target="ISO-GLOSSARY" format="default" sectionFormat="of" derivedContent="ISO-GLOSSARY"/> set.</t>
            <t pn="section-2.1.1.2-4">Examples include "US" for the United States, "JP" for Japan,
	    and "PL" for Poland.</t>
          </section>
          <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.1.3">
            <name slugifiedName="name-region">Region</name>
            <t pn="section-2.1.1.3-1"><bcp14>OPTIONAL</bcp14>: The region field, if non-empty,
	    <bcp14>MUST</bcp14> be an ISO region code conforming to ISO 3166-2
	    <xref target="ISO.3166.2" format="default" sectionFormat="of" derivedContent="ISO.3166.2"/>. Parsers
	    <bcp14>SHOULD</bcp14> treat this field case-insensitively.</t>
            <t pn="section-2.1.1.3-2">Examples include "ID-RI" for the Riau province of Indonesia and
            "NG-RI" for the Rivers province in Nigeria.</t>
          </section>
          <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.1.4">
            <name slugifiedName="name-city">City</name>
            <t pn="section-2.1.1.4-1"><bcp14>OPTIONAL</bcp14>: The city field, if non-empty,
	    <bcp14>SHOULD</bcp14> be free UTF-8 
            text, excluding the comma (',') character.</t>
            <t pn="section-2.1.1.4-2">Examples include "Dublin", "New York", and "Sao Paulo"
            (specifically "S" followed by 0xc3, 0xa3, and "o Paulo").</t>
          </section>
          <section anchor="postal" numbered="true" toc="include" removeInRFC="false" pn="section-2.1.1.5">
            <name slugifiedName="name-postal-code">Postal Code</name>
            <t pn="section-2.1.1.5-1"><bcp14>OPTIONAL</bcp14>, DEPRECATED: The postal code field, if
	    non-empty, <bcp14>SHOULD</bcp14> be free UTF-8 text, excluding the
	    comma (',') character. The use of this field is deprecated;
	    consumers of feeds should be able to parse feeds containing these
	    fields, but new feeds <bcp14>SHOULD NOT</bcp14> include this
	    field due to the granularity of this information. See <xref target="privacy" format="default" sectionFormat="of" derivedContent="Section 4"/> for additional discussion.</t>
            <t pn="section-2.1.1.5-2">Examples include "106-6126" (in Minato ward, Tokyo, Japan).</t>
          </section>
        </section>
        <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.2">
          <name slugifiedName="name-prefixes-with-no-geolocatio">Prefixes with No Geolocation Information</name>
          <t pn="section-2.1.2-1">Feed publishers may indicate that some IP prefixes should not
          have any associated geolocation information. It may be that some
          prefixes under their administrative control are reserved, not yet
          allocated or deployed, or in the process of being redeployed
          elsewhere and existing geolocation information can, from the
          perspective of the publisher, safely be discarded.</t>
          <t pn="section-2.1.2-2">This special case can be indicated by explicitly leaving blank
          all fields that specify any degree of geolocation information. For
          example: </t>
          <artwork name="" type="" align="left" alt="" pn="section-2.1.2-3">
192.0.2.0/24,,,,
2001:db8:1::/48,,,,
2001:db8:2::/48,,,,
</artwork>
          <t pn="section-2.1.2-4">Historically, the user-assigned alpha2code identifier of "ZZ" has
	  been used for this same purpose. This is not necessarily preferred,
	  and no specific interpretation of any of the other user-assigned
	  alpha2code codes is currently defined.</t>
        </section>
        <section numbered="true" toc="include" removeInRFC="false" pn="section-2.1.3">
          <name slugifiedName="name-additional-parsing-requirem">Additional Parsing Requirements</name>
          <t pn="section-2.1.3-1">Feed entries that do not have an IP address or prefix field or have an
	  IP address or prefix field that fails to parse correctly
	  <bcp14>MUST</bcp14> be discarded.</t>
          <t pn="section-2.1.3-2">While publishers <bcp14>SHOULD</bcp14> follow <xref target="RFC5952" format="default" sectionFormat="of" derivedContent="RFC5952"/> for IPv6 prefix fields,
	  consumers <bcp14>MUST</bcp14> nevertheless accept all valid string
	  representations.</t>
          <t pn="section-2.1.3-3">Duplicate IP address or prefix entries <bcp14>MUST</bcp14> be
	  considered an error, and consumer implementations
	  <bcp14>SHOULD</bcp14> log the repeated entries for further
	  administrative review. Publishers <bcp14>SHOULD</bcp14> take
	  measures to ensure there is one and only one entry per IP address
	  and prefix.</t>
          <t pn="section-2.1.3-4">Multiple entries that constitute nested prefixes are
	  permitted. Consumers <bcp14>SHOULD</bcp14> consider the entry with
	  the longest matching prefix (i.e., the "most specific") to be the
	  best matching entry for a given IP address.</t>
          <t pn="section-2.1.3-5">Feed entries with non-empty optional fields that fail to parse,
          either in part or in full, <bcp14>SHOULD</bcp14> be discarded. It is
	  <bcp14>RECOMMENDED</bcp14> that they also be logged for further
	  administrative review.</t>
          <t pn="section-2.1.3-6">For compatibility with future additional fields, a parser
	  <bcp14>MUST</bcp14> ignore any fields beyond those it expects. The
	  data from fields that are expected and that parse successfully
	  <bcp14>MUST</bcp14> still be considered valid. Per <xref target="future_work" format="default" sectionFormat="of" derivedContent="Section 7"/>, no extensions to this format
	  are in use nor are any anticipated.</t>
        </section>
      </section>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-2.2">
        <name slugifiedName="name-examples">Examples</name>
        <t pn="section-2.2-1">Example entries using different IP address formats and describing
	locations at alpha2code ("country code"), region, and city granularity
	level, respectively: </t>
        <artwork name="" type="" align="left" alt="" pn="section-2.2-2">
192.0.2.0/25,US,US-AL,,
192.0.2.5,US,US-AL,Alabaster,
192.0.2.128/25,PL,PL-MZ,,
2001:db8::/32,PL,,,
2001:db8:cafe::/48,PL,PL-MZ,,
</artwork>
        <t pn="section-2.2-3">The IETF network publishes geolocation information for the meeting
        prefixes, and generally just comment out the last meeting information
        and append the new meeting information. The <xref target="GEO_IETF" format="default" sectionFormat="of" derivedContent="GEO_IETF"/>, at the time of this writing, contains:


        </t>
        <artwork name="" type="" align="left" alt="" pn="section-2.2-4">
# IETF106 (Singapore) - November 2019 - Singapore, SG
130.129.0.0/16,SG,SG-01,Singapore,
2001:df8::/32,SG,SG-01,Singapore,
31.133.128.0/18,SG,SG-01,Singapore,
31.130.224.0/20,SG,SG-01,Singapore,
2001:67c:1230::/46,SG,SG-01,Singapore,
2001:67c:370::/48,SG,SG-01,Singapore,
</artwork>
        <t pn="section-2.2-5">Experimentally, RIPE has published geolocation information for
        their conference network prefixes, which change location in accordance
        with each new event. <xref target="GEO_RIPE_NCC" format="default" sectionFormat="of" derivedContent="GEO_RIPE_NCC"/>, at the time of
        writing, contains:</t>
        <artwork name="" type="" align="left" alt="" pn="section-2.2-6">
193.0.24.0/21,NL,NL-ZH,Rotterdam,
2001:67c:64::/48,NL,NL-ZH,Rotterdam,
</artwork>
        <t pn="section-2.2-7">Similarly, ICANN has published geolocation information for their
        portable conference network prefixes. <xref target="GEO_ICANN" format="default" sectionFormat="of" derivedContent="GEO_ICANN"/>, at
        the time of writing, contains: </t>
        <artwork name="" type="" align="left" alt="" pn="section-2.2-8">
199.91.192.0/21,MA,MA-07,Marrakech
2620:f:8000::/48,MA,MA-07,Marrakech
</artwork>
        <t pn="section-2.2-9">A longer example is the <xref target="GEO_Google" format="default" sectionFormat="of" derivedContent="GEO_Google"/> Google Corp
        Geofeed, which lists the geolocation information for Google corporate
        offices.</t>
        <t pn="section-2.2-10">At the time of writing, Google processes approximately 400 feeds
        comprising more than 750,000 IPv4 and IPv6 prefixes.</t>
      </section>
    </section>
    <section anchor="consumers" numbered="true" toc="include" removeInRFC="false" pn="section-3">
      <name slugifiedName="name-consuming-self-published-ip">Consuming Self-Published IP Geolocation Feeds</name>
      <t pn="section-3-1">Consumers <bcp14>MAY</bcp14> treat published feed data as a hint only
      and <bcp14>MAY</bcp14> choose 
      to prefer other sources of geolocation information for any given IP
      prefix. Regardless of a consumer's stance with respect to a given
      published feed, there are some points of note for sensibly and
      effectively consuming published feeds.</t>
      <section anchor="integrity" numbered="true" toc="include" removeInRFC="false" pn="section-3.1">
        <name slugifiedName="name-feed-integrity">Feed Integrity</name>
        <t pn="section-3.1-1">The integrity of published information <bcp14>SHOULD</bcp14> be
	protected by securing the means of publication, for example, by using
	HTTP over TLS <xref target="RFC2818" format="default" sectionFormat="of" derivedContent="RFC2818"/>. Whenever
	possible, consumers <bcp14>SHOULD</bcp14> prefer retrieving
	geolocation feeds in a manner that guarantees integrity of the
	feed.</t>
      </section>
      <section anchor="authority" numbered="true" toc="include" removeInRFC="false" pn="section-3.2">
        <name slugifiedName="name-verification-of-authority">Verification of Authority</name>
        <t pn="section-3.2-1">Consumers of self-published IP geolocation feeds <bcp14>SHOULD</bcp14> perform
        some form of verification that the publisher is in fact authoritative
        for the addresses in the feed. The actual means of verification is
        likely dependent upon the way in which the feed is discovered. Ad hoc
        shared URIs, for example, will likely require an ad hoc verification
        process. Future automated means of feed discovery <bcp14>SHOULD</bcp14> have an
        accompanying automated means of verification.</t>
        <t pn="section-3.2-2">A consumer should only trust geolocation information for IP addresses
        or prefixes for which the publisher has been verified as
        administratively authoritative. All other geolocation feed entries
        should be ignored and logged for further administrative review.</t>
      </section>
      <section anchor="accuracy" numbered="true" toc="include" removeInRFC="false" pn="section-3.3">
        <name slugifiedName="name-verification-of-accuracy">Verification of Accuracy</name>
        <t pn="section-3.3-1">Errors and inaccuracies may occur at many levels, and publication
        and consumption of geolocation data are no exceptions. To the extent
        practical, consumers <bcp14>SHOULD</bcp14> take steps to verify the accuracy of
        published locality. Verification methodology, resolution of
        discrepancies, and preference for alternative sources of data are left
        to the discretion of the feed consumer.</t>
        <t pn="section-3.3-2">Consumers <bcp14>SHOULD</bcp14> decide on discrepancy thresholds
	and <bcp14>SHOULD</bcp14> flag, for administrative review, feed entries
	that exceed set thresholds.</t>
      </section>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-3.4">
        <name slugifiedName="name-refreshing-feed-information">Refreshing Feed Information</name>
        <t pn="section-3.4-1">As a publisher can change geolocation data at any time and without
        notification, consumers <bcp14>SHOULD</bcp14> implement mechanisms to periodically
        refresh local copies of feed data. In the absence of any other refresh
        timing information, it is recommended that consumers <bcp14>SHOULD</bcp14> refresh
        feeds no less often than weekly and no more often than is likely
        to cause issues to the publisher.</t>
        <t pn="section-3.4-2">For feeds available via HTTPS (or HTTP), the publisher <bcp14>MAY</bcp14>
        communicate refresh timing information by means of the standard HTTP
        expiration model (<xref target="RFC7234" format="default" sectionFormat="of" derivedContent="RFC7234"/>). Specifically, publishers can 
        include either an Expires header (<xref target="RFC7234" sectionFormat="of" section="5.3" format="default" derivedLink="https://rfc-editor.org/rfc/rfc7234#section-5.3" derivedContent="RFC7234"/>) or a Cache-Control header (<xref target="RFC7234" sectionFormat="of" section="5.2" format="default" derivedLink="https://rfc-editor.org/rfc/rfc7234#section-5.2" derivedContent="RFC7234"/>) specifying the
	max-age. Where practical, consumers <bcp14>SHOULD</bcp14> refresh feed
	information before the expiry time is reached.</t>
      </section>
    </section>
    <section anchor="privacy" numbered="true" toc="include" removeInRFC="false" pn="section-4">
      <name slugifiedName="name-privacy-considerations">Privacy Considerations</name>
      <t pn="section-4-1">Publishers of geolocation feeds are advised to have fully considered
      any and all privacy implications of the disclosure of such information
      for the users of the described networks prior to publication. A thorough
      comprehension of the security considerations (<xref target="RFC6772" sectionFormat="of" section="13" format="default" derivedLink="https://rfc-editor.org/rfc/rfc6772#section-13" derivedContent="RFC6772"/>) of a chosen geolocation policy is
      highly recommended, including an understanding of some of the
      limitations of information obscurity (<xref target="RFC6772" sectionFormat="of" section="13.5" format="default" derivedLink="https://rfc-editor.org/rfc/rfc6772#section-13.5" derivedContent="RFC6772"/>) (see also <xref target="RFC6772" format="default" sectionFormat="of" derivedContent="RFC6772"/>).</t>
      <t pn="section-4-2">As noted in <xref target="spec" format="default" sectionFormat="of" derivedContent="Section 2.1"/>, each location
      field in an entry is 
      optional, in order to support expressing only the level of specificity
      that the publisher has deemed acceptable. There is no requirement that
      the level of specificity be consistent across all entries within a feed.
      In particular, the Postal Code field (<xref target="postal" format="default" sectionFormat="of" derivedContent="Section 2.1.1.5"/>) can
      provide very specific geolocation, sometimes within a building. Such
      specific Postal Code values <bcp14>MUST NOT</bcp14> be published in geofeeds without
      the express consent of the parties being located.</t>
      <t pn="section-4-3">Operators who publish geolocation information are strongly encouraged
      to inform affected users/customers of this fact and of the potential
      privacy-related consequences and trade-offs.</t>
    </section>
    <section numbered="true" toc="include" removeInRFC="false" pn="section-5">
      <name slugifiedName="name-relation-to-other-work">Relation to Other Work</name>
      <t pn="section-5-1">While not originally done in conjunction with the GEOPRIV
      Working Group <xref target="GEOPRIV" format="default" sectionFormat="of" derivedContent="GEOPRIV"/>, Richard Barnes
      observed that this work 
      is nevertheless consistent with that which the group has defined, both
      for address format and for privacy. The data elements in geolocation
      feeds are equivalent to the following XML structure (<xref target="RFC5139" format="default" sectionFormat="of" derivedContent="RFC5139"/> <xref target="W3C.REC-xml-20081126" format="default" sectionFormat="of" derivedContent="W3C.REC-xml-20081126"/>):


      </t>
      <sourcecode type="xml" markers="false" pn="section-5-2">
&lt;civicAddress&gt;
  &lt;country&gt;country&lt;/country&gt;
  &lt;A1&gt;region&lt;/A1&gt;
  &lt;A2&gt;city&lt;/A2&gt;
  &lt;PC&gt;postal_code&lt;/PC&gt;
&lt;/civicAddress&gt;
</sourcecode>
      <t pn="section-5-3">Providing geolocation information to this granularity is equivalent
      to the following privacy policy (the definition of the 'building'
      <xref target="RFC6772" sectionFormat="of" section="6.5.1" format="default" derivedLink="https://rfc-editor.org/rfc/rfc6772#section-6.5.1" derivedContent="RFC6772"/> level of
      disclosure):</t>
      <sourcecode type="xml" markers="false" pn="section-5-4">
&lt;ruleset&gt;
  &lt;rule&gt;
    &lt;conditions/&gt;
    &lt;actions/&gt;
    &lt;transformations&gt;
      &lt;provide-location profile="civic-transformation"&gt;
        &lt;provide-civic&gt;building&lt;/provide-civic&gt;
      &lt;/provide-location&gt;
    &lt;/transformations&gt;
  &lt;/rule&gt;
&lt;/ruleset&gt;
</sourcecode>
    </section>
    <section anchor="Security" numbered="true" toc="include" removeInRFC="false" pn="section-6">
      <name slugifiedName="name-security-considerations">Security Considerations</name>
      <t pn="section-6-1">As there is no true security in the obscurity of the location of any
      given IP address, self-publication of this data fundamentally opens no
      new attack vectors. For publishers, self-published data may increase
      the ease with which such location data might be exploited (it can, for
      example, make easy the discovery of prefixes populated with customers
      as distinct from prefixes not generally in use).</t>
      <t pn="section-6-2">For consumers, feed retrieval processes may receive input from
      potentially hostile sources (e.g., in the event of hijacked traffic). As
      such, proper input validation and defense measures <bcp14>MUST</bcp14> be taken (see
      the discussion in <xref target="integrity" format="default" sectionFormat="of" derivedContent="Section 3.1"/>).</t>
      <t pn="section-6-3">Similarly, consumers who do not perform sufficient verification of
      published data bear the same risks as from other forms of geolocation
      configuration errors (see the discussion in Sections <xref target="authority" format="counter" sectionFormat="of" derivedContent="3.2"/> 
      and <xref target="accuracy" format="counter" sectionFormat="of" derivedContent="3.3"/>).</t>
      <t pn="section-6-4">Validation of a feed's contents includes verifying that the publisher
      is authoritative for the IP prefixes included in the feed. Failure to
      verify IP prefix authority would, for example, allow ISP Bob to make
      geolocation statements about IP space held by ISP Alice. At this time,
      only out-of-band verification methods are implemented (i.e., an ISP's
      feed may be verified against publicly available IP allocation data).
      </t>
    </section>
    <section anchor="future_work" numbered="true" toc="include" removeInRFC="false" pn="section-7">
      <name slugifiedName="name-planned-future-work">Planned Future Work</name>
      <t pn="section-7-1">In order to more flexibly support future extensions, use of a more
      expressive feed format has been suggested. Use of JavaScript Object
      Notation (JSON) <xref target="RFC8259" format="default" sectionFormat="of" derivedContent="RFC8259"/>,
      specifically, has been 
      discussed. However, at the time of writing, no such specification nor
      implementation exists. Nevertheless, work on extensions is deferred
      until a more suitable format has been selected.</t>
      <t pn="section-7-2">The authors are planning on writing a document describing such a
      new format. This document describes a currently deployed and used
      format. Given the extremely limited extensibility of the present format
      no extensions to it are anticipated. Extensibility requirements are
      instead expected to be integral to the development of a new format.</t>
    </section>
    <section numbered="true" toc="include" removeInRFC="false" pn="section-8">
      <name slugifiedName="name-finding-self-published-ip-g">Finding Self-Published IP Geolocation Feeds</name>
      <t pn="section-8-1">The issue of finding, and later verifying, geolocation feeds is not
      formally specified in this document. At this time, only ad hoc feed
      discovery and verification has a modicum of established practice (see
      below); discussion of other mechanisms has been removed for clarity.</t>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-8.1">
        <name slugifiedName="name-ad-hoc-well-known-uris">Ad Hoc 'Well-Known' URIs</name>
        <t pn="section-8.1-1">To date, geolocation feeds have been shared informally in the form
        of HTTPS URIs exchanged in email threads. Three example URIs (<xref target="GEO_IETF" format="default" sectionFormat="of" derivedContent="GEO_IETF"/>, <xref target="GEO_RIPE_NCC" format="default" sectionFormat="of" derivedContent="GEO_RIPE_NCC"/>, and <xref target="GEO_ICANN" format="default" sectionFormat="of" derivedContent="GEO_ICANN"/>)
	describe networks that change locations periodically, the operators
	and operational practices of which are well known within their
	respective technical communities.</t>
        <t pn="section-8.1-2">The contents of the feeds are verified by a similarly ad hoc
        process, including: </t>
        <ul spacing="normal" bare="false" empty="false" pn="section-8.1-3">
          <li pn="section-8.1-3.1">personal knowledge of the parties involved in the exchange
	  and</li>
          <li pn="section-8.1-3.2">comparison of feed-advertised prefixes with the BGP-advertised
	  prefixes of Autonomous System Numbers known to be operated by the
	  publishers.</li>
        </ul>
        <t pn="section-8.1-4">Ad hoc mechanisms, while useful for early experimentation by
        producers and consumers, are unlikely to be adequate for long-term,
        widespread use by multiple parties. Future versions of any such
        self-published geolocation feed mechanism <bcp14>SHOULD</bcp14> address scalability
        concerns by defining a means for automated discovery and verification
        of operational authority of advertised prefixes.</t>
      </section>
      <section numbered="true" toc="include" removeInRFC="false" pn="section-8.2">
        <name slugifiedName="name-other-mechanisms">Other Mechanisms</name>
        <t pn="section-8.2-1">Previous versions of this document referenced use of the
        WHOIS service <xref target="RFC3912" format="default" sectionFormat="of" derivedContent="RFC3912"/> operated by
	Regional Internet Registries (RIRs), as well as
        possible DNS-based schemes to discover and validate geofeeds.
        To the authors' knowledge, support for such mechanisms has never been
        implemented, and this speculative text has been removed to avoid
        ambiguity.</t>
      </section>
    </section>
    <section numbered="true" toc="include" removeInRFC="false" pn="section-9">
      <name slugifiedName="name-iana-considerations">IANA Considerations</name>
      <t pn="section-9-1">This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references pn="section-10">
      <name slugifiedName="name-references">References</name>
      <references pn="section-10.1">
        <name slugifiedName="name-normative-references">Normative References</name>
        <reference anchor="ISO.3166.1alpha2" target="http://www.iso.org/iso/home/standards/country_codes/iso-3166-1_decoding_table.htm" quoteTitle="true" derivedAnchor="ISO.3166.1alpha2">
          <front>
            <title>ISO 3166-1 decoding table</title>
            <author>
              <organization showOnFrontPage="true">ISO</organization>
            </author>
          </front>
        </reference>
        <reference anchor="ISO.3166.2" target="http://www.iso.org/iso/home/standards/country_codes.htm#2012_iso3166-2" quoteTitle="true" derivedAnchor="ISO.3166.2">
          <front>
            <title>ISO 3166-2:2007</title>
            <author>
              <organization showOnFrontPage="true">ISO</organization>
            </author>
          </front>
        </reference>
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119" quoteTitle="true" derivedAnchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="1997" month="March"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification.  These words are often capitalized. This document defines these words as they should be interpreted in IETF documents.  This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC3629" target="https://www.rfc-editor.org/info/rfc3629" quoteTitle="true" derivedAnchor="RFC3629">
          <front>
            <title>UTF-8, a transformation format of ISO 10646</title>
            <author initials="F." surname="Yergeau" fullname="F. Yergeau">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2003" month="November"/>
            <abstract>
              <t>ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world's writing systems.  The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo.  UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values.  This memo obsoletes and replaces RFC 2279.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="63"/>
          <seriesInfo name="RFC" value="3629"/>
          <seriesInfo name="DOI" value="10.17487/RFC3629"/>
        </reference>
        <reference anchor="RFC4180" target="https://www.rfc-editor.org/info/rfc4180" quoteTitle="true" derivedAnchor="RFC4180">
          <front>
            <title>Common Format and MIME Type for Comma-Separated Values (CSV) Files</title>
            <author initials="Y." surname="Shafranovich" fullname="Y. Shafranovich">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2005" month="October"/>
            <abstract>
              <t>This RFC documents the format used for Comma-Separated Values (CSV) files and registers the associated MIME type "text/csv".  This memo provides information for the Internet community.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="4180"/>
          <seriesInfo name="DOI" value="10.17487/RFC4180"/>
        </reference>
        <reference anchor="RFC4291" target="https://www.rfc-editor.org/info/rfc4291" quoteTitle="true" derivedAnchor="RFC4291">
          <front>
            <title>IP Version 6 Addressing Architecture</title>
            <author initials="R." surname="Hinden" fullname="R. Hinden">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="S." surname="Deering" fullname="S. Deering">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2006" month="February"/>
            <abstract>
              <t>This specification defines the addressing architecture of the IP Version 6 (IPv6) protocol.  The document includes the IPv6 addressing model, text representations of IPv6 addresses, definition of IPv6 unicast addresses, anycast addresses, and multicast addresses, and an IPv6 node's required addresses.</t>
              <t>This document obsoletes RFC 3513, "IP Version 6 Addressing Architecture".   [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="4291"/>
          <seriesInfo name="DOI" value="10.17487/RFC4291"/>
        </reference>
        <reference anchor="RFC4632" target="https://www.rfc-editor.org/info/rfc4632" quoteTitle="true" derivedAnchor="RFC4632">
          <front>
            <title>Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan</title>
            <author initials="V." surname="Fuller" fullname="V. Fuller">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="T." surname="Li" fullname="T. Li">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2006" month="August"/>
            <abstract>
              <t>This memo discusses the strategy for address assignment of the existing 32-bit IPv4 address space with a view toward conserving the address space and limiting the growth rate of global routing state. This document obsoletes the original Classless Inter-domain Routing (CIDR) spec in RFC 1519, with changes made both to clarify the concepts it introduced and, after more than twelve years, to update the Internet community on the results of deploying the technology described.  This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="122"/>
          <seriesInfo name="RFC" value="4632"/>
          <seriesInfo name="DOI" value="10.17487/RFC4632"/>
        </reference>
        <reference anchor="RFC5952" target="https://www.rfc-editor.org/info/rfc5952" quoteTitle="true" derivedAnchor="RFC5952">
          <front>
            <title>A Recommendation for IPv6 Address Text Representation</title>
            <author initials="S." surname="Kawamura" fullname="S. Kawamura">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="M." surname="Kawashima" fullname="M. Kawashima">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2010" month="August"/>
            <abstract>
              <t>As IPv6 deployment increases, there will be a dramatic increase in the need to use IPv6 addresses in text.  While the IPv6 address architecture in Section 2.2 of RFC 4291 describes a flexible model for text representation of an IPv6 address, this flexibility has been causing problems for operators, system engineers, and users.  This document defines a canonical textual representation format.  It does not define a format for internal storage, such as within an application or database.  It is expected that the canonical format will be followed by humans and systems when representing IPv6 addresses as text, but all implementations must accept and be able to handle any legitimate RFC 4291 format.  [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="5952"/>
          <seriesInfo name="DOI" value="10.17487/RFC5952"/>
        </reference>
        <reference anchor="RFC7234" target="https://www.rfc-editor.org/info/rfc7234" quoteTitle="true" derivedAnchor="RFC7234">
          <front>
            <title>Hypertext Transfer Protocol (HTTP/1.1): Caching</title>
            <author initials="R." surname="Fielding" fullname="R. Fielding" role="editor">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="M." surname="Nottingham" fullname="M. Nottingham" role="editor">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="J." surname="Reschke" fullname="J. Reschke" role="editor">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2014" month="June"/>
            <abstract>
              <t>The Hypertext Transfer Protocol (HTTP) is a stateless \%application- level protocol for distributed, collaborative, hypertext information systems.  This document defines HTTP caches and the associated header fields that control cache behavior or indicate cacheable response messages.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7234"/>
          <seriesInfo name="DOI" value="10.17487/RFC7234"/>
        </reference>
        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174" quoteTitle="true" derivedAnchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2017" month="May"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol  specifications.  This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the  defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="W3C.REC-xml-20081126" target="http://www.w3.org/TR/2008/REC-xml-20081126" quoteTitle="true" derivedAnchor="W3C.REC-xml-20081126">
          <front>
            <title>Extensible Markup Language (XML) 1.0 (Fifth Edition)</title>
            <author initials="T." surname="Bray" fullname="Tim Bray">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="J." surname="Paoli" fullname="Jean Paoli">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="M." surname="Sperberg-McQueen" fullname="Michael Sperberg-McQueen">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="E." surname="Maler" fullname="Eve Maler">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="F." surname="Yergeau" fullname="François Yergeau">
              <organization showOnFrontPage="true"/>
            </author>
            <date month="November" year="2008"/>
          </front>
          <seriesInfo name="World Wide Web Consortium Recommendation" value="REC-xml-20081126"/>
          <format type="HTML" target="http://www.w3.org/TR/2008/REC-xml-20081126"/>
        </reference>
      </references>
      <references pn="section-10.2">
        <name slugifiedName="name-informative-references">Informative References</name>
        <reference anchor="GEOPRIV" target="http://datatracker.ietf.org/wg/geopriv/" quoteTitle="true" derivedAnchor="GEOPRIV">
          <front>
            <title>Geographic Location/Privacy (geopriv)</title>
            <author>
              <organization showOnFrontPage="true">IETF</organization>
            </author>
            <date/>
          </front>
        </reference>
        <reference anchor="GEO_Google" target="https://www.gstatic.com/geofeed/corp_external" quoteTitle="true" derivedAnchor="GEO_Google">
          <front>
            <title>Google Corp Geofeed</title>
            <author>
              <organization showOnFrontPage="true">Google, LLC</organization>
            </author>
          </front>
        </reference>
        <reference anchor="GEO_ICANN" target="https://meeting-services.icann.org/geo/google.csv" quoteTitle="true" derivedAnchor="GEO_ICANN">
          <front>
            <title>ICANN Meeting Geolocation Data</title>
            <author>
              <organization showOnFrontPage="true">ICANN</organization>
            </author>
          </front>
        </reference>
        <reference anchor="GEO_IETF" target="https://noc.ietf.org/geo/google.csv" quoteTitle="true" derivedAnchor="GEO_IETF">
          <front>
            <title>IETF Meeting Network Geolocation Data</title>
            <author initials="W." surname="Kumari" fullname="Warren Kumari">
              <organization showOnFrontPage="true"/>
            </author>
          </front>
        </reference>
        <reference anchor="GEO_RIPE_NCC" target="https://meetings.ripe.net/geo/google.csv" quoteTitle="true" derivedAnchor="GEO_RIPE_NCC">
          <front>
            <title>RIPE NCC Meeting Geolocation Data</title>
            <author fullname="Menno Schepers" initials="M." surname="Schepers">
              <organization abbrev="RIPE NCC" showOnFrontPage="true">Réseaux IP Européens Network Coordination Centre</organization>
            </author>
          </front>
        </reference>
        <reference anchor="IPADDR_PY" target="http://code.google.com/p/ipaddr-py/" quoteTitle="true" derivedAnchor="IPADDR_PY">
          <front>
            <title>Google's Python IP address manipulation library</title>
            <author fullname="Mike Shields" initials="M." surname="Shields">
              <organization abbrev="Google" showOnFrontPage="true">Google Inc.</organization>
            </author>
            <author fullname="Peter Moody" initials="P." surname="Moody">
              <organization abbrev="Google" showOnFrontPage="true">Google Inc.</organization>
            </author>
            <date/>
          </front>
        </reference>
        <reference anchor="ISO-GLOSSARY" target="https://www.iso.org/glossary-for-iso-3166.html" quoteTitle="true" derivedAnchor="ISO-GLOSSARY">
          <front>
            <title>Glossary for ISO 3166</title>
            <author>
              <organization showOnFrontPage="true">ISO</organization>
            </author>
            <date/>
          </front>
        </reference>
        <reference anchor="RFC2818" target="https://www.rfc-editor.org/info/rfc2818" quoteTitle="true" derivedAnchor="RFC2818">
          <front>
            <title>HTTP Over TLS</title>
            <author initials="E." surname="Rescorla" fullname="E. Rescorla">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2000" month="May"/>
            <abstract>
              <t>This memo describes how to use Transport Layer Security (TLS) to secure Hypertext Transfer Protocol (HTTP) connections over the Internet.  This memo provides information for the Internet community.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="2818"/>
          <seriesInfo name="DOI" value="10.17487/RFC2818"/>
        </reference>
        <reference anchor="RFC3912" target="https://www.rfc-editor.org/info/rfc3912" quoteTitle="true" derivedAnchor="RFC3912">
          <front>
            <title>WHOIS Protocol Specification</title>
            <author initials="L." surname="Daigle" fullname="L. Daigle">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2004" month="September"/>
            <abstract>
              <t>This document updates the specification of the WHOIS protocol, thereby obsoleting RFC 954.  The update is intended to remove the material from RFC 954 that does not have to do with the on-the-wire protocol, and is no longer applicable in today's Internet.  This document does not attempt to change or update the protocol per se, or document other uses of the protocol that have come into existence since the publication of RFC 954.  [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="3912"/>
          <seriesInfo name="DOI" value="10.17487/RFC3912"/>
        </reference>
        <reference anchor="RFC5139" target="https://www.rfc-editor.org/info/rfc5139" quoteTitle="true" derivedAnchor="RFC5139">
          <front>
            <title>Revised Civic Location Format for Presence Information Data Format Location Object (PIDF-LO)</title>
            <author initials="M." surname="Thomson" fullname="M. Thomson">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="J." surname="Winterbottom" fullname="J. Winterbottom">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2008" month="February"/>
            <abstract>
              <t>This document defines an XML format for the representation of civic location.  This format is designed for use with Presence Information Data Format Location Object (PIDF-LO) documents and replaces the civic location format in RFC 4119.  The format is based on the civic address definition in PIDF-LO, but adds several new elements based on the civic types defined for Dynamic Host Configuration Protocol (DHCP), and adds a hierarchy to address complex road identity schemes.  The format also includes support for the xml:lang language tag and restricts the types of elements where appropriate.  [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="5139"/>
          <seriesInfo name="DOI" value="10.17487/RFC5139"/>
        </reference>
        <reference anchor="RFC6772" target="https://www.rfc-editor.org/info/rfc6772" quoteTitle="true" derivedAnchor="RFC6772">
          <front>
            <title>Geolocation Policy: A Document Format for Expressing Privacy Preferences for Location Information</title>
            <author initials="H." surname="Schulzrinne" fullname="H. Schulzrinne" role="editor">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="H." surname="Tschofenig" fullname="H. Tschofenig" role="editor">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="J." surname="Cuellar" fullname="J. Cuellar">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="J." surname="Polk" fullname="J. Polk">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="J." surname="Morris" fullname="J. Morris">
              <organization showOnFrontPage="true"/>
            </author>
            <author initials="M." surname="Thomson" fullname="M. Thomson">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2013" month="January"/>
            <abstract>
              <t>This document defines an authorization policy language for controlling access to location information.  It extends the Common Policy authorization framework to provide location-specific access control.  More specifically, this document defines condition elements specific to location information in order to restrict access to data based on the current location of the Target.</t>
              <t>Furthermore, this document defines two algorithms for reducing the granularity of returned location information.  The first algorithm is defined for usage with civic location information, whereas the other one applies to geodetic location information.  Both algorithms come with limitations.  There are circumstances where the amount of location obfuscation provided is less than what is desired.  These algorithms might not be appropriate for all application domains. [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="6772"/>
          <seriesInfo name="DOI" value="10.17487/RFC6772"/>
        </reference>
        <reference anchor="RFC7208" target="https://www.rfc-editor.org/info/rfc7208" quoteTitle="true" derivedAnchor="RFC7208">
          <front>
            <title>Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1</title>
            <author initials="S." surname="Kitterman" fullname="S. Kitterman">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2014" month="April"/>
            <abstract>
              <t>Email on the Internet can be forged in a number of ways.  In particular, existing protocols place no restriction on what a sending host can use as the "MAIL FROM" of a message or the domain given on the SMTP HELO/EHLO commands.  This document describes version 1 of the Sender Policy Framework (SPF) protocol, whereby ADministrative Management Domains (ADMDs) can explicitly authorize the hosts that are allowed to use their domain names, and a receiving host can check such authorization.</t>
              <t>This document obsoletes RFC 4408.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7208"/>
          <seriesInfo name="DOI" value="10.17487/RFC7208"/>
        </reference>
        <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259" quoteTitle="true" derivedAnchor="RFC8259">
          <front>
            <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
            <author initials="T." surname="Bray" fullname="T. Bray" role="editor">
              <organization showOnFrontPage="true"/>
            </author>
            <date year="2017" month="December"/>
            <abstract>
              <t>JavaScript Object Notation (JSON) is a lightweight, text-based, language-independent data interchange format.  It was derived from the ECMAScript Programming Language Standard.  JSON defines a small set of formatting rules for the portable representation of structured data.</t>
              <t>This document removes inconsistencies with other specifications of JSON, repairs specification errors, and offers experience-based interoperability guidance.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
          <seriesInfo name="DOI" value="10.17487/RFC8259"/>
        </reference>
      </references>
    </references>
    <section numbered="true" toc="include" removeInRFC="false" pn="section-appendix.a">
      <name slugifiedName="name-sample-python-validation-co">Sample Python Validation Code</name>
      <t pn="section-appendix.a-1">Included here is a simple format validator in Python for
      self-published ipgeo feeds. This tool reads CSV data in the
      self-published ipgeo feed format from the standard input and performs
      basic validation.  It is intended for use by feed publishers before
      launching a feed. Note that this validator does not verify the
      uniqueness of every IP prefix entry within the feed as a whole but only
      verifies the syntax of each single line from within the feed. A complete
      validator <bcp14>MUST</bcp14> also ensure IP prefix uniqueness.</t>
      <t pn="section-appendix.a-2">The main source file "ipgeo_feed_validator.py" follows. It requires
      use of the open source ipaddr Python library for IP address and CIDR
      parsing and validation <xref target="IPADDR_PY" format="default" sectionFormat="of" derivedContent="IPADDR_PY"/>.</t>
      <sourcecode name="" type="python" markers="true" pn="section-appendix.a-3">
#!/usr/bin/python
#
# Copyright (c) 2012 IETF Trust and the persons identified as
# authors of the code.  All rights reserved.  Redistribution and use
# in source and binary forms, with or without modification, is
# permitted pursuant to, and subject to the license terms contained
# in, the Simplified BSD License set forth in Section 4.c of the
# IETF Trust's Legal Provisions Relating to IETF
# Documents (http://trustee.ietf.org/license-info).

"""Simple format validator for self-published ipgeo feeds.

This tool reads CSV data in the self-published ipgeo feed format
from the standard input and performs basic validation.  It is
intended for use by feed publishers before launching a feed.
"""

import csv
import ipaddr
import re
import sys


class IPGeoFeedValidator(object):
  def __init__(self):
    self.prefixes = {}
    self.line_number = 0
    self.output_log = {}
    self.SetOutputStream(sys.stderr)

  def Validate(self, feed):
    """Check validity of an IPGeo feed.

    Args:
      feed: iterable with feed lines
    """

    for line in feed:
      self._ValidateLine(line)

  def SetOutputStream(self, logfile):
    """Controls where the output messages go do (STDERR by default).

    Use None to disable logging.

    Args:
      logfile: a file object (e.g., sys.stdout) or None.
    """
    self.output_stream = logfile

  def CountErrors(self, severity):
    """How many ERRORs or WARNINGs were generated."""
    return len(self.output_log.get(severity, []))

  ############################################################
  def _ValidateLine(self, line):
    line = line.rstrip('\r\n')
    self.line_number += 1
    self.line = line.split('#')[0]
    self.is_correct_line = True

    if self._ShouldIgnoreLine(line):
      return

    fields = [field for field in csv.reader([line])][0]

    self._ValidateFields(fields)
    self._FlushOutputStream()

  def _ShouldIgnoreLine(self, line):
    line = line.strip()
    if line.startswith('#'):
      return True
    return len(line) == 0

  ############################################################
  def _ValidateFields(self, fields):
    assert(len(fields) &gt; 0)

    is_correct = self._IsIPAddressOrPrefixCorrect(fields[0])

    if len(fields) &gt; 1:
      if not self._IsAlpha2CodeCorrect(fields[1]):
        is_correct = False

    if len(fields) &gt; 2 and not self._IsRegionCodeCorrect(fields[2]):
      is_correct = False

    if len(fields) != 5:
      self._ReportWarning('5 fields were expected (got %d).'
                          % len(fields))

  ############################################################
  def _IsIPAddressOrPrefixCorrect(self, field):
    if '/' in field:
      return self._IsCIDRCorrect(field)
    return self._IsIPAddressCorrect(field)

  def _IsCIDRCorrect(self, cidr):
    try:
      ipprefix = ipaddr.IPNetwork(cidr)
      if ipprefix.network._ip != ipprefix._ip:
        self._ReportError('Incorrect IP Network.')
        return False
      if ipprefix.is_private:
        self._ReportError('IP Address must not be private.')
        return False
    except:
      self._ReportError('Incorrect IP Network.')
      return False
    return True

  def _IsIPAddressCorrect(self, ipaddress):
    try:
      ip = ipaddr.IPAddress(ipaddress)
    except:
      self._ReportError('Incorrect IP Address.')
      return False
    if ip.is_private:
      self._ReportError('IP Address must not be private.')
      return False
    return True

  ############################################################
  def _IsAlpha2CodeCorrect(self, alpha2code):
    if len(alpha2code) == 0:
      return True
    if len(alpha2code) != 2 or not alpha2code.isalpha():
      self._ReportError(
          'Alpha 2 code must be in the ISO 3166-1 alpha 2 format.')
      return False
    return True

  def _IsRegionCodeCorrect(self, region_code):
    if len(region_code) == 0:
      return True
    if '-' not in region_code:
      self._ReportError('Region code must be in ISO 3166-2 format.')
      return False

    parts = region_code.split('-')
    if not self._IsAlpha2CodeCorrect(parts[0]):
      return False
    return True

  ############################################################
  def _ReportError(self, message):
    self._ReportWithSeverity('ERROR', message)

  def _ReportWarning(self, message):
    self._ReportWithSeverity('WARNING', message)

  def _ReportWithSeverity(self, severity, message):
    self.is_correct_line = False
    output_line = '%s: %s\n' % (severity, message)

    if severity not in self.output_log:
      self.output_log[severity] = []
    self.output_log[severity].append(output_line)

    if self.output_stream is not None:
      self.output_stream.write(output_line)

  def _FlushOutputStream(self):
    if self.is_correct_line: return
    if self.output_stream is None: return

    self.output_stream.write('line %d: %s\n\n'
                             % (self.line_number, self.line))


############################################################
def main():
   feed_validator = IPGeoFeedValidator()
   feed_validator.Validate(sys.stdin)

   if feed_validator.CountErrors('ERROR'):
     sys.exit(1)

if __name__ == '__main__':
  main()
</sourcecode>
      <t pn="section-appendix.a-4">A unit test file, "ipgeo_feed_validator_test.py" is provided as well.
      It provides basic test coverage of the code above, though does not test
      correct handling of non-ASCII UTF-8 strings.</t>
      <sourcecode name="" type="python" markers="true" pn="section-appendix.a-5">
#!/usr/bin/python
#
# Copyright (c) 2012 IETF Trust and the persons identified as
# authors of the code.  All rights reserved.  Redistribution and use
# in source and binary forms, with or without modification, is
# permitted pursuant to, and subject to the license terms contained
# in, the Simplified BSD License set forth in Section 4.c of the
# IETF Trust's Legal Provisions Relating to IETF
# Documents (http://trustee.ietf.org/license-info).

import sys
from ipgeo_feed_validator import IPGeoFeedValidator

class IPGeoFeedValidatorTest(object):
  def __init__(self):
    self.validator = IPGeoFeedValidator()
    self.validator.SetOutputStream(None)
    self.successes = 0
    self.failures = 0

  def Run(self):
    self.TestFeedLine('# asdf', 0, 0)
    self.TestFeedLine('   ', 0, 0)
    self.TestFeedLine('', 0, 0)

    self.TestFeedLine('asdf', 1, 1)
    self.TestFeedLine('asdf,US,,,', 1, 0)
    self.TestFeedLine('aaaa::,US,,,', 0, 0)
    self.TestFeedLine('zzzz::,US', 1, 1)
    self.TestFeedLine(',US,,,', 1, 0)
    self.TestFeedLine('55.66.77', 1, 1)
    self.TestFeedLine('55.66.77.888', 1, 1)
    self.TestFeedLine('55.66.77.asdf', 1, 1)

    self.TestFeedLine('2001:db8:cafe::/48,PL,PL-MZ,,02-784', 0, 0)
    self.TestFeedLine('2001:db8:cafe::/48', 0, 1)

    self.TestFeedLine('55.66.77.88,PL', 0, 1)
    self.TestFeedLine('55.66.77.88,PL,,,', 0, 0)
    self.TestFeedLine('55.66.77.88,,,,', 0, 0)
    self.TestFeedLine('55.66.77.88,ZZ,,,', 0, 0)
    self.TestFeedLine('55.66.77.88,US,,,', 0, 0)
    self.TestFeedLine('55.66.77.88,USA,,,', 1, 0)
    self.TestFeedLine('55.66.77.88,99,,,', 1, 0)

    self.TestFeedLine('55.66.77.88,US,US-CA,,', 0, 0)
    self.TestFeedLine('55.66.77.88,US,USA-CA,,', 1, 0)
    self.TestFeedLine('55.66.77.88,USA,USA-CA,,', 2, 0)

    self.TestFeedLine('55.66.77.88,US,US-CA,Mountain View,', 0, 0)
    self.TestFeedLine('55.66.77.88,US,US-CA,Mountain View,94043',
                      0, 0)
    self.TestFeedLine('55.66.77.88,US,US-CA,Mountain View,94043,'
                      '1600 Ampthitheatre Parkway', 0, 1)

    self.TestFeedLine('55.66.77.0/24,US,,,', 0, 0)
    self.TestFeedLine('55.66.77.88/24,US,,,', 1, 0)
    self.TestFeedLine('55.66.77.88/32,US,,,', 0, 0)
    self.TestFeedLine('55.66.77/24,US,,,', 1, 0)
    self.TestFeedLine('55.66.77.0/35,US,,,', 1, 0)

    self.TestFeedLine('172.15.30.1,US,,,', 0, 0)
    self.TestFeedLine('172.28.30.1,US,,,', 1, 0)
    self.TestFeedLine('192.167.100.1,US,,,', 0, 0)
    self.TestFeedLine('192.168.100.1,US,,,', 1, 0)
    self.TestFeedLine('10.0.5.9,US,,,', 1, 0)
    self.TestFeedLine('10.0.5.0/24,US,,,', 1, 0)
    self.TestFeedLine('fc00::/48,PL,,,', 1, 0)
    self.TestFeedLine('fe00::/48,PL,,,', 0, 0)

    print ('%d tests passed, %d failed'
      % (self.successes, self.failures))

  def IsOutputLogCorrectAtSeverity(self, severity,
    expected_msg_count):
    msg_count = self.validator.CountErrors(severity)

    if msg_count != expected_msg_count:
      print ('TEST FAILED: %s\nexpected %d %s[s], observed %d\n%s\n'
         % (self.validator.line, expected_msg_count, severity,
           msg_count,
          str(self.validator.output_log[severity])))
      return False
    return True

  def IsOutputLogCorrect(self, new_errors, new_warnings):
    retval = True

    if not self.IsOutputLogCorrectAtSeverity('ERROR', new_errors):
      retval = False
    if not self.IsOutputLogCorrectAtSeverity('WARNING',
                                             new_warnings):
      retval = False

    return retval

  def TestFeedLine(self, line, warning_count, error_count):
    self.validator.output_log['WARNING'] = []
    self.validator.output_log['ERROR'] = []
    self.validator._ValidateLine(line)

    if not self.IsOutputLogCorrect(warning_count, error_count):
      self.failures += 1
      return False

    self.successes += 1
    return True


if __name__ == '__main__':
  IPGeoFeedValidatorTest().Run()
</sourcecode>
    </section>
    <section numbered="false" toc="include" removeInRFC="false" pn="section-appendix.b">
      <name slugifiedName="name-acknowledgements">Acknowledgements</name>
      <t pn="section-appendix.b-1">The authors would like to express their gratitude to reviewers and
      early implementors, including but not limited to <contact fullname="Mikael Abrahamsson"/>, <contact fullname="Andrew Alston"/>,
      <contact fullname="Ray Bellis"/>, <contact fullname="John Bond"/>,
      <contact fullname="Alissa Cooper"/>, <contact fullname="Andras Erdei"/>,
      <contact fullname="Stephen Farrell"/>, <contact fullname="Marco       Hogewoning"/>, <contact fullname="Mike Joseph"/>, <contact fullname="Maciej Kuzniar"/>, <contact fullname="George Michaelson"/>,
      <contact fullname="Menno Schepers"/>, <contact fullname="Justyna       Sidorska"/>, <contact fullname="Pim van Pelt"/>, and <contact fullname="Bjoern A. Zeeb"/>.</t>
      <t pn="section-appendix.b-2">In particular, <contact fullname="Richard L. Barnes"/> and <contact fullname="Andy Newton"/> contributed substantial review,
      text, and advice.</t>
    </section>
    <section anchor="authors-addresses" numbered="false" removeInRFC="false" toc="include" pn="section-appendix.c">
      <name slugifiedName="name-authors-addresses">Authors' Addresses</name>
      <author fullname="Erik Kline" initials="E." surname="Kline">
        <organization showOnFrontPage="true">Loon LLC</organization>
        <address>
          <postal>
            <street>1600 Amphitheatre Parkway</street>
            <city>Mountain View</city>
            <region>CA</region>
            <code>94043</code>
            <country>United States of America</country>
          </postal>
          <email>ek@loon.com</email>
        </address>
      </author>
      <author fullname="Krzysztof Duleba" initials="K." surname="Duleba">
        <organization showOnFrontPage="true">Google</organization>
        <address>
          <postal>
            <street>1600 Amphitheatre Parkway</street>
            <city>Mountain View</city>
            <region>CA</region>
            <code>94043</code>
            <country>United States of America</country>
          </postal>
          <email>kduleba@google.com</email>
        </address>
      </author>
      <author fullname="Zoltan Szamonek" initials="Z." surname="Szamonek">
        <organization showOnFrontPage="true">Google Switzerland GmbH</organization>
        <address>
          <postal>
            <street>Brandschenkestrasse 110</street>
            <code>8002</code>
            <city>Zürich</city>
            <country>Switzerland</country>
          </postal>
          <email>zszami@google.com</email>
        </address>
      </author>
      <author fullname="Stefan Moser" initials="S." surname="Moser">
        <organization showOnFrontPage="true">Google Switzerland GmbH</organization>
        <address>
          <postal>
            <street>Brandschenkestrasse 110</street>
            <code>8002</code>
            <city>Zürich</city>
            <country>Switzerland</country>
          </postal>
          <email>smoser@google.com</email>
        </address>
      </author>
      <author fullname="Warren Kumari" initials="W." surname="Kumari">
        <organization showOnFrontPage="true">Google</organization>
        <address>
          <postal>
            <street>1600 Amphitheatre Parkway</street>
            <city>Mountain View</city>
            <region>CA</region>
            <code>94043</code>
            <country>United States of America</country>
          </postal>
          <email>warren@kumari.net</email>
        </address>
      </author>
    </section>
  </back>
</rfc>
