2 ###############################################################################
4 # libloc - A library to determine the location of someone on the Internet #
6 # Copyright (C) 2017 IPFire Development Team <info@ipfire.org> #
8 # This library is free software; you can redistribute it and/or #
9 # modify it under the terms of the GNU Lesser General Public #
10 # License as published by the Free Software Foundation; either #
11 # version 2.1 of the License, or (at your option) any later version. #
13 # This library is distributed in the hope that it will be useful, #
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
16 # Lesser General Public License for more details. #
18 ###############################################################################
28 # Load our location module
32 def _(singular
, plural
=None, n
=None):
34 return gettext
.dngettext("libloc", singular
, plural
, n
)
36 return gettext
.dgettext("libloc", singular
)
40 class OutputFormatter(object):
47 def __exit__(self
, type, value
, tb
):
57 def network(self
, network
):
61 class XTGeoIPOutputFormatter(OutputFormatter
):
63 Formats the output in that way, that it can be loaded by
64 the xt_geoip kernel module from xtables-addons.
66 def network(self
, network
):
67 n
= ipaddress
.ip_network("%s" % network
)
69 for address
in (n
.network_address
, n
.broadcast_address
):
70 bytes
= socket
.inet_pton(
71 socket
.AF_INET6
if address
.version
== 6 else socket
.AF_INET
,
80 "list" : OutputFormatter
,
81 "xt_geoip" : XTGeoIPOutputFormatter
,
85 parser
= argparse
.ArgumentParser(
86 description
=_("Location Database Command Line Interface"),
88 subparsers
= parser
.add_subparsers()
90 # Global configuration flags
91 parser
.add_argument("--debug", action
="store_true",
92 help=_("Enable debug output"))
95 parser
.add_argument("--version", action
="version",
96 version
="%%(prog)s %s" % location
.__version
__)
99 parser
.add_argument("--database", "-d",
100 default
="@databasedir@/database.db", help=_("Path to database"),
103 # lookup an IP address
104 lookup
= subparsers
.add_parser("lookup",
105 help=_("Lookup one or multiple IP addresses"),
107 lookup
.add_argument("address", nargs
="+")
108 lookup
.set_defaults(func
=self
.handle_lookup
)
111 get_as
= subparsers
.add_parser("get-as",
112 help=_("Get information about one or multiple Autonomous Systems"),
114 get_as
.add_argument("asn", nargs
="+")
115 get_as
.set_defaults(func
=self
.handle_get_as
)
118 search_as
= subparsers
.add_parser("search-as",
119 help=_("Search for Autonomous Systems that match the string"),
121 search_as
.add_argument("query", nargs
=1)
122 search_as
.set_defaults(func
=self
.handle_search_as
)
124 # List all networks in an AS
125 list_networks_by_as
= subparsers
.add_parser("list-networks-by-as",
126 help=_("Lists all networks in an AS"),
128 list_networks_by_as
.add_argument("asn", nargs
=1, type=int)
129 list_networks_by_as
.add_argument("--output-format",
130 choices
=self
.output_formats
.keys(), default
="list")
131 list_networks_by_as
.set_defaults(func
=self
.handle_list_networks_by_as
)
133 # List all networks in a country
134 list_networks_by_cc
= subparsers
.add_parser("list-networks-by-cc",
135 help=_("Lists all networks in a country"),
137 list_networks_by_cc
.add_argument("country_code", nargs
=1)
138 list_networks_by_cc
.add_argument("--output-format",
139 choices
=self
.output_formats
.keys(), default
="list")
140 list_networks_by_cc
.set_defaults(func
=self
.handle_list_networks_by_cc
)
142 args
= parser
.parse_args()
144 # Print usage if no action was given
145 if not "func" in args
:
152 # Parse command line arguments
153 args
= self
.parse_cli()
157 db
= location
.Database(args
.database
)
158 except FileNotFoundError
as e
:
159 sys
.stderr
.write("location-query: Could not open database %s: %s\n" \
160 % (args
.database
, e
))
164 ret
= args
.func(db
, args
)
166 # Return with exit code
170 # Otherwise just exit
173 def handle_lookup(self
, db
, ns
):
176 for address
in ns
.address
:
178 n
= db
.lookup(address
)
180 print(_("Invalid IP address: %s") % address
, file=sys
.stderr
)
189 print(_("Nothing found for %(address)s") % args
, file=sys
.stderr
)
193 # Try to retrieve the AS if we have an AS number
197 # If we have found an AS we will print it in the message
203 print(_("%(address)s belongs to %(network)s which is a part of %(as)s") % args
)
206 print(_("%(address)s belongs to %(network)s") % args
)
210 def handle_get_as(self
, db
, ns
):
212 Gets information about Autonomous Systems
220 print(_("Invalid ASN: %s") % asn
, file=sys
.stderr
)
224 # Fetch AS from database
229 print(_("Could not find AS%s") % asn
, file=sys
.stderr
)
233 print(_("AS%(asn)s belongs to %(name)s") % { "asn" : a
.number
, "name" : a
.name
})
237 def handle_search_as(self
, db
, ns
):
238 for query
in ns
.query
:
239 # Print all matches ASes
240 for a
in db
.search_as(query
):
243 def __get_output_formatter(self
, ns
):
245 cls
= self
.output_formats
[ns
.output_format
]
247 cls
= OutputFormatter
251 def handle_list_networks_by_as(self
, db
, ns
):
252 with self
.__get
_output
_formatter
(ns
) as f
:
254 # Print all matching networks
255 for n
in db
.search_networks(asn
=asn
):
258 def handle_list_networks_by_cc(self
, db
, ns
):
259 with self
.__get
_output
_formatter
(ns
) as f
:
260 for country_code
in ns
.country_code
:
261 # Print all matching networks
262 for n
in db
.search_networks(country_code
=country_code
):
267 # Run the command line interface