[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnunet-go] branch master updated: MS2-RC1: Recursive resolution and han
From: |
gnunet |
Subject: |
[gnunet-go] branch master updated: MS2-RC1: Recursive resolution and handling of GNS-specific RRs. |
Date: |
Wed, 18 Dec 2019 17:24:03 +0100 |
This is an automated email from the git hooks/post-receive script.
bernd-fix pushed a commit to branch master
in repository gnunet-go.
The following commit(s) were added to refs/heads/master by this push:
new caf6245 MS2-RC1: Recursive resolution and handling of GNS-specific
RRs.
caf6245 is described below
commit caf624535c2089e01ecc6d4c74f056472b3e54e0
Author: Bernd Fix <address@hidden>
AuthorDate: Wed Dec 18 17:19:32 2019 +0100
MS2-RC1: Recursive resolution and handling of GNS-specific RRs.
---
LICENSE | 849 +++++++++++++++++++++++---------
README.md | 1 +
src/gnunet/config/config.go | 13 +-
src/gnunet/core/peer.go | 36 +-
src/gnunet/crypto/gns.go | 35 ++
src/gnunet/crypto/gns_test.go | 150 ++++++
src/gnunet/crypto/hash.go | 3 +
src/gnunet/crypto/key_derivation.go | 1 +
src/gnunet/crypto/key_exchange.go | 4 +-
src/gnunet/crypto/signature.go | 1 +
src/gnunet/crypto/symmetric.go | 19 +-
src/gnunet/enums/dht.go | 23 +
src/gnunet/enums/gns.go | 1 +
src/gnunet/message/message.go | 8 +
src/gnunet/message/msg_core.go | 33 +-
src/gnunet/message/msg_dht.go | 2 +
src/gnunet/message/msg_gns.go | 16 +-
src/gnunet/message/msg_namecache.go | 4 +-
src/gnunet/message/msg_transport.go | 207 +++++---
src/gnunet/service/client.go | 3 +-
src/gnunet/service/gns/block.go | 185 +++++++
src/gnunet/service/gns/block_handler.go | 398 +++++++++++++++
src/gnunet/service/gns/box.go | 151 ++++++
src/gnunet/service/gns/dns.go | 61 ++-
src/gnunet/service/gns/module.go | 257 ++++------
src/gnunet/service/gns/service.go | 12 +-
src/gnunet/service/service.go | 13 +-
src/gnunet/transport/channel.go | 1 +
src/gnunet/transport/channel_netw.go | 39 +-
src/gnunet/transport/connection.go | 9 +-
src/gnunet/transport/session.go | 3 +-
src/gnunet/util/address.go | 55 ++-
src/gnunet/util/array.go | 10 +
src/gnunet/util/format.go | 13 +-
src/gnunet/util/id.go | 3 +-
src/gnunet/util/peer_id.go | 3 +
src/gnunet/util/rnd.go | 8 +
37 files changed, 2030 insertions(+), 600 deletions(-)
diff --git a/LICENSE b/LICENSE
index 0a4f9a1..6cfcd65 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,235 +1,616 @@
-GNU AFFERO GENERAL PUBLIC LICENSE
-Version 3, 19 November 2007
-
-Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
+Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
-Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.
-
- Preamble
-
-The GNU Affero General Public License is a free, copyleft license for software
and other kinds of works, specifically designed to ensure cooperation with the
community in the case of network server software.
-
-The licenses for most software and other practical works are designed to take
away your freedom to share and change the works. By contrast, our General
Public Licenses are intended to guarantee your freedom to share and change all
versions of a program--to make sure it remains free software for all its users.
-
-When we speak of free software, we are referring to freedom, not price. Our
General Public Licenses are designed to make sure that you have the freedom to
distribute copies of free software (and charge for them if you wish), that you
receive source code or can get it if you want it, that you can change the
software or use pieces of it in new free programs, and that you know you can do
these things.
-
-Developers that use our General Public Licenses protect your rights with two
steps: (1) assert copyright on the software, and (2) offer you this License
which gives you legal permission to copy, distribute and/or modify the software.
-
-A secondary benefit of defending all users' freedom is that improvements made
in alternate versions of the program, if they receive widespread use, become
available for other developers to incorporate. Many developers of free
software are heartened and encouraged by the resulting cooperation. However,
in the case of software used on network servers, this result may fail to come
about. The GNU General Public License permits making a modified version and
letting the public access it on a [...]
-
-The GNU Affero General Public License is designed specifically to ensure that,
in such cases, the modified source code becomes available to the community. It
requires the operator of a network server to provide the source code of the
modified version running there to the users of that server. Therefore, public
use of a modified version, on a publicly accessible server, gives the public
access to the source code of the modified version.
-
-An older license, called the Affero General Public License and published by
Affero, was designed to accomplish similar goals. This is a different license,
not a version of the Affero GPL, but Affero has released a new version of the
Affero GPL which permits relicensing under this license.
-
-The precise terms and conditions for copying, distribution and modification
follow.
-
- TERMS AND CONDITIONS
-
-0. Definitions.
-
-"This License" refers to version 3 of the GNU Affero General Public License.
-
-"Copyright" also means copyright-like laws that apply to other kinds of works,
such as semiconductor masks.
-
-"The Program" refers to any copyrightable work licensed under this License.
Each licensee is addressed as "you". "Licensees" and "recipients" may be
individuals or organizations.
-
-To "modify" a work means to copy from or adapt all or part of the work in a
fashion requiring copyright permission, other than the making of an exact copy.
The resulting work is called a "modified version" of the earlier work or a
work "based on" the earlier work.
-
-A "covered work" means either the unmodified Program or a work based on the
Program.
-
-To "propagate" a work means to do anything with it that, without permission,
would make you directly or secondarily liable for infringement under applicable
copyright law, except executing it on a computer or modifying a private copy.
Propagation includes copying, distribution (with or without modification),
making available to the public, and in some countries other activities as well.
-
-To "convey" a work means any kind of propagation that enables other parties to
make or receive copies. Mere interaction with a user through a computer
network, with no transfer of a copy, is not conveying.
-
-An interactive user interface displays "Appropriate Legal Notices" to the
extent that it includes a convenient and prominently visible feature that (1)
displays an appropriate copyright notice, and (2) tells the user that there is
no warranty for the work (except to the extent that warranties are provided),
that licensees may convey the work under this License, and how to view a copy
of this License. If the interface presents a list of user commands or options,
such as a menu, a promine [...]
-
-1. Source Code.
-The "source code" for a work means the preferred form of the work for making
modifications to it. "Object code" means any non-source form of a work.
-
-A "Standard Interface" means an interface that either is an official standard
defined by a recognized standards body, or, in the case of interfaces specified
for a particular programming language, one that is widely used among developers
working in that language.
-
-The "System Libraries" of an executable work include anything, other than the
work as a whole, that (a) is included in the normal form of packaging a Major
Component, but which is not part of that Major Component, and (b) serves only
to enable use of the work with that Major Component, or to implement a Standard
Interface for which an implementation is available to the public in source code
form. A "Major Component", in this context, means a major essential component
(kernel, window sys [...]
-
-The "Corresponding Source" for a work in object code form means all the source
code needed to generate, install, and (for an executable work) run the object
code and to modify the work, including scripts to control those activities.
However, it does not include the work's System Libraries, or general-purpose
tools or generally available free programs which are used unmodified in
performing those activities but which are not part of the work. For example,
Corresponding Source includes i [...]
-subprograms and other parts of the work.
-
-The Corresponding Source need not include anything that users can regenerate
automatically from other parts of the Corresponding Source.
-
-The Corresponding Source for a work in source code form is that same work.
-
-2. Basic Permissions.
-All rights granted under this License are granted for the term of copyright on
the Program, and are irrevocable provided the stated conditions are met. This
License explicitly affirms your unlimited permission to run the unmodified
Program. The output from running a covered work is covered by this License
only if the output, given its content, constitutes a covered work. This
License acknowledges your rights of fair use or other equivalent, as provided
by copyright law.
-
-You may make, run and propagate covered works that you do not convey, without
conditions so long as your license otherwise remains in force. You may convey
covered works to others for the sole purpose of having them make modifications
exclusively for you, or provide you with facilities for running those works,
provided that you comply with the terms of this License in conveying all
material for which you do not control copyright. Those thus making or running
the covered works for you m [...]
-
-Conveying under any other circumstances is permitted solely under the
conditions stated below. Sublicensing is not allowed; section 10 makes it
unnecessary.
-
-3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-No covered work shall be deemed part of an effective technological measure
under any applicable law fulfilling obligations under article 11 of the WIPO
copyright treaty adopted on 20 December 1996, or similar laws prohibiting or
restricting circumvention of such measures.
-
-When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention is
effected by exercising rights under this License with respect to the covered
work, and you disclaim any intention to limit operation or modification of the
work as a means of enforcing, against the work's users, your or third parties'
legal rights to forbid circumvention of technological measures.
-
-4. Conveying Verbatim Copies.
-You may convey verbatim copies of the Program's source code as you receive it,
in any medium, provided that you conspicuously and appropriately publish on
each copy an appropriate copyright notice; keep intact all notices stating that
this License and any non-permissive terms added in accord with section 7 apply
to the code; keep intact all notices of the absence of any warranty; and give
all recipients a copy of this License along with the Program.
-
-You may charge any price or no price for each copy that you convey, and you
may offer support or warranty protection for a fee.
-
-5. Conveying Modified Source Versions.
-You may convey a work based on the Program, or the modifications to produce it
from the Program, in the form of source code under the terms of section 4,
provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified it, and
giving a relevant date.
-
- b) The work must carry prominent notices stating that it is released under
this License and any conditions added under section 7. This requirement
modifies the requirement in section 4 to "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this License to
anyone who comes into possession of a copy. This License will therefore apply,
along with any applicable section 7 additional terms, to the whole of the work,
and all its parts, regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not invalidate
such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive interfaces
that do not display Appropriate Legal Notices, your work need not make them do
so.
-
-A compilation of a covered work with other separate and independent works,
which are not by their nature extensions of the covered work, and which are not
combined with it such as to form a larger program, in or on a volume of a
storage or distribution medium, is called an "aggregate" if the compilation and
its resulting copyright are not used to limit the access or legal rights of the
compilation's users beyond what the individual works permit. Inclusion of a
covered work in an aggrega [...]
-
-6. Conveying Non-Source Forms.
-You may convey a covered work in object code form under the terms of sections
4 and 5, provided that you also convey the machine-readable Corresponding
Source under the terms of this License, in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the Corresponding
Source fixed on a durable physical medium customarily used for software
interchange.
-
- b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a written offer,
valid for at least three years and valid for as long as you offer spare parts
or customer support for that product model, to give anyone who possesses the
object code either (1) a copy of the Corresponding Source for all the software
in the product that is covered by this License, on a durable physical medium
customarily used for software interc [...]
-
- c) Convey individual copies of the object code with a copy of the written
offer to provide the Corresponding Source. This alternative is allowed only
occasionally and noncommercially, and only if you received the object code with
such an offer, in accord with subsection 6b.
-
- d) Convey the object code by offering access from a designated place
(gratis or for a charge), and offer equivalent access to the Corresponding
Source in the same way through the same place at no further charge. You need
not require recipients to copy the Corresponding Source along with the object
code. If the place to copy the object code is a network server, the
Corresponding Source may be on a different server (operated by you or a third
party) that supports equivalent copying f [...]
-
- e) Convey the object code using peer-to-peer transmission, provided you
inform other peers where the object code and Corresponding Source of the work
are being offered to the general public at no charge under subsection 6d.
-
-A separable portion of the object code, whose source code is excluded from the
Corresponding Source as a System Library, need not be included in conveying the
object code work.
-
-A "User Product" is either (1) a "consumer product", which means any tangible
personal property which is normally used for personal, family, or household
purposes, or (2) anything designed or sold for incorporation into a dwelling.
In determining whether a product is a consumer product, doubtful cases shall be
resolved in favor of coverage. For a particular product received by a
particular user, "normally used" refers to a typical or common use of that
class of product, regardless of t [...]
-
-"Installation Information" for a User Product means any methods, procedures,
authorization keys, or other information required to install and execute
modified versions of a covered work in that User Product from a modified
version of its Corresponding Source. The information must suffice to ensure
that the continued functioning of the modified object code is in no case
prevented or interfered with solely because modification has been made.
-
-If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as part of a
transaction in which the right of possession and use of the User Product is
transferred to the recipient in perpetuity or for a fixed term (regardless of
how the transaction is characterized), the Corresponding Source conveyed under
this section must be accompanied by the Installation Information. But this
requirement does not apply if neith [...]
-
-The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates for a
work that has been modified or installed by the recipient, or for the User
Product in which it has been modified or installed. Access to a network may be
denied when the modification itself materially and adversely affects the
operation of the network or violates the rules and protocols for communication
across the network.
-
-Corresponding Source conveyed, and Installation Information provided, in
accord with this section must be in a format that is publicly documented (and
with an implementation available to the public in source code form), and must
require no special password or key for unpacking, reading or copying.
-
-7. Additional Terms.
-"Additional permissions" are terms that supplement the terms of this License
by making exceptions from one or more of its conditions. Additional permissions
that are applicable to the entire Program shall be treated as though they were
included in this License, to the extent that they are valid under applicable
law. If additional permissions apply only to part of the Program, that part
may be used separately under those permissions, but the entire Program remains
governed by this Licens [...]
-
-When you convey a copy of a covered work, you may at your option remove any
additional permissions from that copy, or from any part of it. (Additional
permissions may be written to require their own removal in certain cases when
you modify the work.) You may place additional permissions on material, added
by you to a covered work, for which you have or can give appropriate copyright
permission.
-
-Notwithstanding any other provision of this License, for material you add to a
covered work, you may (if authorized by the copyright holders of that material)
supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the terms
of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or author
attributions in that material or in the Appropriate Legal Notices displayed by
works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in reasonable ways
as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some trade
names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that material by
anyone who conveys the material (or modified versions of it) with contractual
assumptions of liability to the recipient, for any liability that these
contractual assumptions directly impose on those licensors and authors.
-
-All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you received
it, or any part of it, contains a notice stating that it is governed by this
License along with a term that is a further restriction, you may remove that
term. If a license document contains a further restriction but permits
relicensing or conveying under this License, you may add to a covered work
material governed by the terms of that licens [...]
-
-If you add terms to a covered work in accord with this section, you must
place, in the relevant source files, a statement of the additional terms that
apply to those files, or a notice indicating where to find the applicable terms.
-
-Additional terms, permissive or non-permissive, may be stated in the form of a
separately written license, or stated as exceptions; the above requirements
apply either way.
-
-8. Termination.
-
-You may not propagate or modify a covered work except as expressly provided
under this License. Any attempt otherwise to propagate or modify it is void,
and will automatically terminate your rights under this License (including any
patent licenses granted under the third paragraph of section 11).
-
-However, if you cease all violation of this License, then your license from a
particular copyright holder is reinstated (a) provisionally, unless and until
the copyright holder explicitly and finally terminates your license, and (b)
permanently, if the copyright holder fails to notify you of the violation by
some reasonable means prior to 60 days after the cessation.
-
-Moreover, your license from a particular copyright holder is reinstated
permanently if the copyright holder notifies you of the violation by some
reasonable means, this is the first time you have received notice of violation
of this License (for any work) from that copyright holder, and you cure the
violation prior to 30 days after your receipt of the notice.
-
-Termination of your rights under this section does not terminate the licenses
of parties who have received copies or rights from you under this License. If
your rights have been terminated and not permanently reinstated, you do not
qualify to receive new licenses for the same material under section 10.
-
-9. Acceptance Not Required for Having Copies.
-
-You are not required to accept this License in order to receive or run a copy
of the Program. Ancillary propagation of a covered work occurring solely as a
consequence of using peer-to-peer transmission to receive a copy likewise does
not require acceptance. However, nothing other than this License grants you
permission to propagate or modify any covered work. These actions infringe
copyright if you do not accept this License. Therefore, by modifying or
propagating a covered work, yo [...]
-
-10. Automatic Licensing of Downstream Recipients.
-
-Each time you convey a covered work, the recipient automatically receives a
license from the original licensors, to run, modify and propagate that work,
subject to this License. You are not responsible for enforcing compliance by
third parties with this License.
-
-An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered work
results from an entity transaction, each party to that transaction who receives
a copy of the work also receives whatever licenses to the work the party's
predecessor in interest had or could give under the previous paragraph, plus a
right to possession of the Corresponding Source [...]
-
-You may not impose any further restrictions on the exercise of the rights
granted or affirmed under this License. For example, you may not impose a
license fee, royalty, or other charge for exercise of rights granted under this
License, and you may not initiate litigation (including a cross-claim or
counterclaim in a lawsuit) alleging that any patent claim is infringed by
making, using, selling, offering for sale, or importing the Program or any
portion of it.
-
-11. Patents.
-
-A "contributor" is a copyright holder who authorizes use under this License of
the Program or a work on which the Program is based. The work thus licensed is
called the contributor's "contributor version".
-
-A contributor's "essential patent claims" are all patent claims owned or
controlled by the contributor, whether already acquired or hereafter acquired,
that would be infringed by some manner, permitted by this License, of making,
using, or selling its contributor version, but do not include claims that would
be infringed only as a consequence of further modification of the contributor
version. For purposes of this definition, "control" includes the right to
grant patent sublicenses in a [...]
-
-Each contributor grants you a non-exclusive, worldwide, royalty-free patent
license under the contributor's essential patent claims, to make, use, sell,
offer for sale, import and otherwise run, modify and propagate the contents of
its contributor version.
-
-In the following three paragraphs, a "patent license" is any express agreement
or commitment, however denominated, not to enforce a patent (such as an express
permission to practice a patent or covenant not to s ue for patent
infringement). To "grant" such a patent license to a party means to make such
an agreement or commitment not to enforce a patent against the party.
-
-If you convey a covered work, knowingly relying on a patent license, and the
Corresponding Source of the work is not available for anyone to copy, free of
charge and under the terms of this License, through a publicly available
network server or other readily accessible means, then you must either (1)
cause the Corresponding Source to be so available, or (2) arrange to deprive
yourself of the benefit of the patent license for this particular work, or (3)
arrange, in a manner consistent w [...]
-license to downstream recipients. "Knowingly relying" means you have actual
knowledge that, but for the patent license, your conveying the covered work in
a country, or your recipient's use of the covered work in a country, would
infringe one or more identifiable patents in that country that you have reason
to believe are valid.
-
-If, pursuant to or in connection with a single transaction or arrangement, you
convey, or propagate by procuring conveyance of, a covered work, and grant a
patent license to some of the parties receiving the covered work authorizing
them to use, propagate, modify or convey a specific copy of the covered work,
then the patent license you grant is automatically extended to all recipients
of the covered work and works based on it.
-
-A patent license is "discriminatory" if it does not include within the scope
of its coverage, prohibits the exercise of, or is conditioned on the
non-exercise of one or more of the rights that are specifically granted under
this License. You may not convey a covered work if you are a party to an
arrangement with a third party that is in the business of distributing
software, under which you make payment to the third party based on the extent
of your activity of conveying the work, and u [...]
-
-Nothing in this License shall be construed as excluding or limiting any
implied license or other defenses to infringement that may otherwise be
available to you under applicable patent law.
-
-12. No Surrender of Others' Freedom.
-
-If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not excuse
you from the conditions of this License. If you cannot convey a covered work
so as to satisfy simultaneously your obligations under this License and any
other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you to
collect a royalty for further conveying from those to whom you convey the
Program, the only way you could satisfy both those terms and this License would
be to refrain entirely from conveying the Program.
-
-13. Remote Network Interaction; Use with the GNU General Public License.
-
-Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users interacting
with it remotely through a computer network (if your version supports such
interaction) an opportunity to receive the Corresponding Source of your version
by providing access to the Corresponding Source from a network server at no
charge, through some standard or customary means of facilitating copying of
software. This Corresponding Source s [...]
-
-Notwithstanding any other provision of this License, you have permission to
link or combine any covered work with a work licensed under version 3 of the
GNU General Public License into a single combined work, and to convey the
resulting work. The terms of this License will continue to apply to the part
which is the covered work, but the work with which it is combined will remain
governed by version 3 of the GNU General Public License.
-
-14. Revised Versions of this License.
-
-The Free Software Foundation may publish revised and/or new versions of the
GNU Affero General Public License from time to time. Such new versions will be
similar in spirit to the present version, but may differ in detail to address
new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
specifies that a certain numbered version of the GNU Affero General Public
License "or any later version" applies to it, you have the option of following
the terms and conditions either of that numbered version or of any later
version published by the Free Software Foundation. If the Program does not
specify a version number of the GNU Affero General Public License, you may
choose any version ever published by the Fr [...]
-
-If the Program specifies that a proxy can decide which future versions of the
GNU Affero General Public License can be used, that proxy's public statement of
acceptance of a version permanently authorizes you to choose that version for
the Program.
-
-Later license versions may give you additional or different permissions.
However, no additional obligations are imposed on any author or copyright
holder as a result of your choosing to follow a later version.
-
-15. Disclaimer of Warranty.
-
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM
PROVE DEFECTIVE, YOU ASSUME TH [...]
-
-16. Limitation of Liability.
-
-IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
PROGRAM TO OPERATE WIT [...]
-
-17. Interpretation of Sections 15 and 16.
-
-If the disclaimer of warranty and limitation of liability provided above
cannot be given local legal effect according to their terms, reviewing courts
shall apply local law that most closely approximates an absolute waiver of all
civil liability in connection with the Program, unless a warranty or assumption
of liability accompanies a copy of the Program in return for a fee.
-
-END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
-If you develop a new program, and you want it to be of the greatest possible
use to the public, the best way to achieve this is to make it free software
which everyone can redistribute and change under these terms.
-
-To do so, attach the following notices to the program. It is safest to attach
them to the start of each source file to most effectively state the exclusion
of warranty; and each file should have at least the "copyright" line and a
pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
-
- This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
for more details.
-
- You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
you should also make sure that it provides a way for users to get its source.
For example, if your program is a web application, its interface could display
a "Source" link that leads users to an archive of the code. There are many
ways you could offer source, and different solutions will be better for
different programs; see section 13 for the specific requirements.
-
-You should also get your employer (if you work as a programmer) or school, if
any, to sign a "copyright disclaimer" for the program, if necessary. For more
information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
\ No newline at end of file
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The GNU Affero General Public License is a free, copyleft license for software
+and other kinds of works, specifically designed to ensure cooperation with the
+community in the case of network server software.
+
+The licenses for most software and other practical works are designed to take
+away your freedom to share and change the works. By contrast, our General
+Public Licenses are intended to guarantee your freedom to share and change all
+versions of a program--to make sure it remains free software for all its users.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for them if you wish), that you
+receive source code or can get it if you want it, that you can change the
+software or use pieces of it in new free programs, and that you know you can
+do these things.
+
+Developers that use our General Public Licenses protect your rights with two
+steps: (1) assert copyright on the software, and (2) offer you this License
+which gives you legal permission to copy, distribute and/or modify the
software.
+
+A secondary benefit of defending all users' freedom is that improvements made
+in alternate versions of the program, if they receive widespread use, become
+available for other developers to incorporate. Many developers of free
+software are heartened and encouraged by the resulting cooperation. However,
+in the case of software used on network servers, this result may fail to come
+about. The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its source code
+to the public.
+
+The GNU Affero General Public License is designed specifically to ensure that,
+in such cases, the modified source code becomes available to the community. It
+requires the operator of a network server to provide the source code of the
+modified version running there to the users of that server. Therefore, public
+use of a modified version, on a publicly accessible server, gives the public
+access to the source code of the modified version.
+
+An older license, called the Affero General Public License and published by
+Affero, was designed to accomplish similar goals. This is a different license,
+not a version of the Affero GPL, but Affero has released a new version of the
+Affero GPL which permits relicensing under this license.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+TERMS AND CONDITIONS
+
+0. Definitions.
+
+"This License" refers to version 3 of the GNU Affero General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of works,
+such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this License.
+Each licensee is addressed as "you". "Licensees" and "recipients" may be
+individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work in a
+fashion requiring copyright permission, other than the making of an exact copy.
+ The resulting work is called a "modified version" of the earlier work or a
+work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based on the
+Program.
+
+To "propagate" a work means to do anything with it that, without permission,
+would make you directly or secondarily liable for infringement under applicable
+copyright law, except executing it on a computer or modifying a private copy.
+Propagation includes copying, distribution (with or without modification),
+making available to the public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other parties to
+make or receive copies. Mere interaction with a user through a computer
+network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to the
+extent that it includes a convenient and prominently visible feature that
+(1) displays an appropriate copyright notice, and (2) tells the user that
+there is no warranty for the work (except to the extent that warranties are
+provided), that licensees may convey the work under this License, and how to
+view a copy of this License. If the interface presents a list of user commands
+or options, such as a menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work for making
+modifications to it. "Object code" means any non-source form of a work.
+
+A "Standard Interface" means an interface that either is an official standard
+defined by a recognized standards body, or, in the case of interfaces specified
+for a particular programming language, one that is widely used among developers
+working in that language.
+
+The "System Libraries" of an executable work include anything, other than the
+work as a whole, that (a) is included in the normal form of packaging a Major
+Component, but which is not part of that Major Component, and (b) serves only
+to enable use of the work with that Major Component, or to implement a Standard
+Interface for which an implementation is available to the public in source code
+form. A "Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system (if any) on
+which the executable work runs, or a compiler used to produce the work, or an
+object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all the source
+code needed to generate, install, and (for an executable work) run the object
+code and to modify the work, including scripts to control those activities.
+However, it does not include the work's System Libraries, or general-purpose
+tools or generally available free programs which are used unmodified in
+performing those activities but which are not part of the work. For example,
+Corresponding Source includes interface definition files associated with source
+files for the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require, such as
+by intimate data communication or control flow between those subprograms and
+other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate
+automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on
+the Program, and are irrevocable provided the stated conditions are met. This
+License explicitly affirms your unlimited permission to run the unmodified
+Program. The output from running a covered work is covered by this License
+only if the output, given its content, constitutes a covered work. This
+License acknowledges your rights of fair use or other equivalent, as provided
+by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without
+conditions so long as your license otherwise remains in force. You may convey
+covered works to others for the sole purpose of having them make modifications
+exclusively for you, or provide you with facilities for running those works,
+provided that you comply with the terms of this License in conveying all
+material for which you do not control copyright. Those thus making or running
+the covered works for you must do so exclusively on your behalf, under your
+direction and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below. Sublicensing is not allowed; section 10 makes it
+unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure
+under any applicable law fulfilling obligations under article 11 of the WIPO
+copyright treaty adopted on 20 December 1996, or similar laws prohibiting or
+restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention is
+effected by exercising rights under this License with respect to the covered
+work, and you disclaim any intention to limit operation or modification of the
+work as a means of enforcing, against the work's users, your or third parties'
+legal rights to forbid circumvention of technological measures.
+
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it,
+in any medium, provided that you conspicuously and appropriately publish on
+each copy an appropriate copyright notice; keep intact all notices stating
+that this License and any non-permissive terms added in accord with section
+7 apply to the code; keep intact all notices of the absence of any warranty;
+and give all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you
+may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it
+from the Program, in the form of source code under the terms of section 4,
+provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified it, and
+ giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is released under
+ this License and any conditions added under section 7. This requirement
+ modifies the requirement in section 4 to "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this License to
+ anyone who comes into possession of a copy. This License will
+ therefore apply, along with any applicable section 7 additional terms,
+ to the whole of the work, and all its parts, regardless of how they are
+ packaged. This License gives no permission to license the work in any
+ other way, but it does not invalidate such permission if you have
+ separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your work
+ need not make them do so.
+
+A compilation of a covered work with other separate and independent works,
+which are not by their nature extensions of the covered work, and which are
+not combined with it such as to form a larger program, in or on a volume of a
+storage or distribution medium, is called an "aggregate" if the compilation
+and its resulting copyright are not used to limit the access or legal rights
+of the compilation's users beyond what the individual works permit. Inclusion
+of a covered work in an aggregate does not cause this License to apply to the
+other parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections
+4 and 5, provided that you also convey the machine-readable Corresponding
+Source under the terms of this License, in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium customarily
+ used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a written
+ offer, valid for at least three years and valid for as long as you
+ offer spare parts or customer support for that product model, to give
+ anyone who possesses the object code either (1) a copy of the
+ Corresponding Source for all the software in the product that is
+ covered by this License, on a durable physical medium customarily used
+ for software interchange, for a price no more than your reasonable cost
+ of physically performing this conveying of source, or (2) access to
+ copy the Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the written
+ offer to provide the Corresponding Source. This alternative is allowed
+ only occasionally and noncommercially, and only if you received the
+ object code with such an offer, in accord with subsection 6b.
+
+ d) Convey the object code by offering access from a designated place
+ (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to copy
+ the object code is a network server, the Corresponding Source may be on
+ a different server (operated by you or a third party) that supports
+ equivalent copying facilities, provided you maintain clear directions
+ next to the object code saying where to find the Corresponding Source.
+ Regardless of what server hosts the Corresponding Source, you remain
+ obligated to ensure that it is available for as long as needed to
+ satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided you
+ inform other peers where the object code and Corresponding Source of
+ the work are being offered to the general public at no charge under
+ subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the
+Corresponding Source as a System Library, need not be included in conveying
+the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any tangible
+personal property which is normally used for personal, family, or household
+purposes, or (2) anything designed or sold for incorporation into a dwelling.
+In determining whether a product is a consumer product, doubtful cases shall
+be resolved in favor of coverage. For a particular product received by a
+particular user, "normally used" refers to a typical or common use of that
+class of product, regardless of the status of the particular user or of the
+way in which the particular user actually uses, or expects or is expected to
+use, the product. A product is a consumer product regardless of whether the
+product has substantial commercial, industrial or non-consumer uses, unless
+such uses represent the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods, procedures,
+authorization keys, or other information required to install and execute
+modified versions of a covered work in that User Product from a modified
+version of its Corresponding Source. The information must suffice to ensure
+that the continued functioning of the modified object code is in no case
+prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as part of
+a transaction in which the right of possession and use of the User Product is
+transferred to the recipient in perpetuity or for a fixed term (regardless of
+how the transaction is characterized), the Corresponding Source conveyed under
+this section must be accompanied by the Installation Information. But this
+requirement does not apply if neither you nor any third party retains the
+ability to install modified object code on the User Product (for example, the
+work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates for a
+work that has been modified or installed by the recipient, or for the User
+Product in which it has been modified or installed. Access to a network may
+be denied when the modification itself materially and adversely affects the
+operation of the network or violates the rules and protocols for communication
+across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in
+accord with this section must be in a format that is publicly documented (and
+with an implementation available to the public in source code form), and must
+require no special password or key for unpacking, reading or copying.
+
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this License
+by making exceptions from one or more of its conditions. Additional permissions
+that are applicable to the entire Program shall be treated as though they were
+included in this License, to the extent that they are valid under applicable
+law. If additional permissions apply only to part of the Program, that part
+may be used separately under those permissions, but the entire Program remains
+governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any
+additional permissions from that copy, or from any part of it. (Additional
+permissions may be written to require their own removal in certain cases when
+you modify the work.) You may place additional permissions on material, added
+by you to a covered work, for which you have or can give appropriate copyright
+permission.
+
+Notwithstanding any other provision of this License, for material you add to a
+covered work, you may (if authorized by the copyright holders of that material)
+supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the terms of
+ sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or author
+ attributions in that material or in the Appropriate Legal Notices
+ displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or authors
+ of the material; or
+
+ e) Declining to grant rights under trademark law for use of some trade
+ names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that material by
+ anyone who conveys the material (or modified versions of it) with
+ contractual assumptions of liability to the recipient, for any liability
+ that these contractual assumptions directly impose on those licensors
+ and authors.
+
+All other non-permissive additional terms are considered "further restrictions"
+within the meaning of section 10. If the Program as you received it, or any
+part of it, contains a notice stating that it is governed by this License along
+with a term that is a further restriction, you may remove that term. If a
+license document contains a further restriction but permits relicensing or
+conveying under this License, you may add to a covered work material governed
+by the terms of that license document, provided that the further restriction
+does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place,
+in the relevant source files, a statement of the additional terms that apply
+to those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a
+separately written license, or stated as exceptions; the above requirements
+apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided
+under this License. Any attempt otherwise to propagate or modify it is void,
+and will automatically terminate your rights under this License (including any
+patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a
+particular copyright holder is reinstated (a) provisionally, unless and until
+the copyright holder explicitly and finally terminates your license, and (b)
+permanently, if the copyright holder fails to notify you of the violation by
+some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated
+permanently if the copyright holder notifies you of the violation by some
+reasonable means, this is the first time you have received notice of violation
+of this License (for any work) from that copyright holder, and you cure the
+violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses
+of parties who have received copies or rights from you under this License.
+If your rights have been terminated and not permanently reinstated, you do not
+qualify to receive new licenses for the same material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy
+of the Program. Ancillary propagation of a covered work occurring solely as a
+consequence of using peer-to-peer transmission to receive a copy likewise does
+not require acceptance. However, nothing other than this License grants you
+permission to propagate or modify any covered work. These actions infringe
+copyright if you do not accept this License. Therefore, by modifying or
+propagating a covered work, you indicate your acceptance of this License to
+do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a
+license from the original licensors, to run, modify and propagate that work,
+subject to this License. You are not responsible for enforcing compliance by
+third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered work
+results from an entity transaction, each party to that transaction who receives
+a copy of the work also receives whatever licenses to the work the party's
+predecessor in interest had or could give under the previous paragraph, plus a
+right to possession of the Corresponding Source of the work from the
+predecessor in interest, if the predecessor has it or can get it with
+reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights
+granted or affirmed under this License. For example, you may not impose a
+license fee, royalty, or other charge for exercise of rights granted under this
+License, and you may not initiate litigation (including a cross-claim or
+counterclaim in a lawsuit) alleging that any patent claim is infringed by
+making, using, selling, offering for sale, or importing the Program or any
+portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this License of
+the Program or a work on which the Program is based. The work thus licensed is
+called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned or
+controlled by the contributor, whether already acquired or hereafter acquired,
+that would be infringed by some manner, permitted by this License, of making,
+using, or selling its contributor version, but do not include claims that would
+be infringed only as a consequence of further modification of the contributor
+version. For purposes of this definition, "control" includes the right to
+grant patent sublicenses in a manner consistent with the requirements of this
+License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent
+license under the contributor's essential patent claims, to make, use, sell,
+offer for sale, import and otherwise run, modify and propagate the contents of
+its contributor version.
+
+In the following three paragraphs, a "patent license" is any express agreement
+or commitment, however denominated, not to enforce a patent (such as an express
+permission to practice a patent or covenant not to s ue for patent
+infringement). To "grant" such a patent license to a party means to make such
an
+agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the
+Corresponding Source of the work is not available for anyone to copy, free of
+charge and under the terms of this License, through a publicly available
+network server or other readily accessible means, then you must either
+(1) cause the Corresponding Source to be so available, or (2) arrange to
+deprive yourself of the benefit of the patent license for this particular work,
+or (3) arrange, in a manner consistent with the requirements of this License,
+to extend the patent license to downstream recipients. "Knowingly relying"
+means you have actual knowledge that, but for the patent license, your
+conveying the covered work in a country, or your recipient's use of the
+covered work in a country, would infringe one or more identifiable patents in
+that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you
+convey, or propagate by procuring conveyance of, a covered work, and grant a
+patent license to some of the parties receiving the covered work authorizing
+them to use, propagate, modify or convey a specific copy of the covered work,
+then the patent license you grant is automatically extended to all recipients
+of the covered work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the scope of
+its coverage, prohibits the exercise of, or is conditioned on the non-exercise
+of one or more of the rights that are specifically granted under this License.
+You may not convey a covered work if you are a party to an arrangement with a
+third party that is in the business of distributing software, under which you
+make payment to the third party based on the extent of your activity of
+conveying the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory patent
+license (a) in connection with copies of the covered work conveyed by you (or
+copies made from those copies), or (b) primarily for and in connection with
+specific products or compilations that contain the covered work, unless you
+entered into that arrangement, or that patent license was granted, prior to
+28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied
+license or other defenses to infringement that may otherwise be available to
+you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not excuse
+you from the conditions of this License. If you cannot convey a covered work
+so as to satisfy simultaneously your obligations under this License and any
+other pertinent obligations, then as a consequence you may not convey it at
+all. For example, if you agree to terms that obligate you to collect a royalty
+for further conveying from those to whom you convey the Program, the only way
+you could satisfy both those terms and this License would be to refrain
+entirely from conveying the Program.
+
+13. Remote Network Interaction; Use with the GNU General Public License.
+
+Notwithstanding any other provision of this License, if you modify the Program,
+your modified version must prominently offer all users interacting with it
+remotely through a computer network (if your version supports such interaction)
+an opportunity to receive the Corresponding Source of your version by providing
+access to the Corresponding Source from a network server at no charge, through
+some standard or customary means of facilitating copying of software. This
+Corresponding Source shall include the Corresponding Source for any work
+covered by version 3 of the GNU General Public License that is incorporated
+pursuant to the following paragraph.
+
+Notwithstanding any other provision of this License, you have permission to
+link or combine any covered work with a work licensed under version 3 of the
+GNU General Public License into a single combined work, and to convey the
+resulting work. The terms of this License will continue to apply to the part
+which is the covered work, but the work with which it is combined will remain
+governed by version 3 of the GNU General Public License.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU
+Affero General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to address
+new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies that a certain numbered version of the GNU Affero General Public
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that numbered version or of any
+later version published by the Free Software Foundation. If the Program does
+not specify a version number of the GNU Affero General Public License, you may
+choose any version ever published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the
+GNU Affero General Public License can be used, that proxy's public statement
+of acceptance of a version permanently authorizes you to choose that version
+for the Program.
+
+Later license versions may give you additional or different permissions.
+However, no additional obligations are imposed on any author or copyright
+holder as a result of your choosing to follow a later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
+LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
+SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+SERVICING, REPAIR OR CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
+PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
+PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot
+be given local legal effect according to their terms, reviewing courts shall
+apply local law that most closely approximates an absolute waiver of all civil
+liability in connection with the Program, unless a warranty or assumption of
+liability accompanies a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach
+them to the start of each source file to most effectively state the exclusion
+of warranty; and each file should have at least the "copyright" line and a
+pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer network,
+you should also make sure that it provides a way for users to get its source.
+For example, if your program is a web application, its interface could display
+a "Source" link that leads users to an archive of the code. There are many
+ways you could offer source, and different solutions will be better for
+different programs; see section 13 for the specific requirements.
+
+You should also get your employer (if you work as a programmer) or school, if
+any, to sign a "copyright disclaimer" for the program, if necessary. For more
+information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/README.md b/README.md
index 1875501..37b1cb8 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,7 @@ packages are accessible through `GOPATH`. To install the
dependencies:
```bash
$ go get -u golang.org/x/crypto/...
$ go get -u golang.org/x/text/...
+$ go get -u github.com/miekg/dns/...
$ go get -u github.com/bfix/gospel/...
```
diff --git a/src/gnunet/config/config.go b/src/gnunet/config/config.go
index 1a53941..eaadd98 100644
--- a/src/gnunet/config/config.go
+++ b/src/gnunet/config/config.go
@@ -7,9 +7,10 @@ import (
"regexp"
"strings"
+ "gnunet/util"
+
"github.com/bfix/gospel/crypto/ed25519"
"github.com/bfix/gospel/logger"
- "gnunet/util"
)
///////////////////////////////////////////////////////////////////////
@@ -64,6 +65,7 @@ type Config struct {
}
var (
+ // Cfg is the global configuration
Cfg *Config
)
@@ -88,6 +90,8 @@ var (
rx = regexp.MustCompile("\\$\\{([^\\}]*)\\}")
)
+// substString is a helper function to substitute environment variables
+// with actual values.
func substString(s string, env map[string]string) string {
matches := rx.FindAllStringSubmatch(s, -1)
for _, m := range matches {
@@ -102,7 +106,8 @@ func substString(s string, env map[string]string) string {
return s
}
-// applySubstitutions
+// applySubstitutions traverses the configuration data structure
+// and applies string substitutions to all string values.
func applySubstitutions(x interface{}, env map[string]string) {
var process func(v reflect.Value)
@@ -140,10 +145,11 @@ func applySubstitutions(x interface{}, env
map[string]string) {
}
}
}
-
+ // start processing at the top-level structure
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Ptr:
+ // indirect top-level
e := v.Elem()
if e.IsValid() {
process(e)
@@ -151,6 +157,7 @@ func applySubstitutions(x interface{}, env
map[string]string) {
logger.Printf(logger.ERROR, "[config] 'nil' pointer
encountered")
}
case reflect.Struct:
+ // direct top-level
process(v)
}
}
diff --git a/src/gnunet/core/peer.go b/src/gnunet/core/peer.go
index ac2d980..d0b3a4c 100644
--- a/src/gnunet/core/peer.go
+++ b/src/gnunet/core/peer.go
@@ -3,30 +3,25 @@ package core
import (
"fmt"
- "github.com/bfix/gospel/crypto/ed25519"
"gnunet/message"
"gnunet/util"
-)
-/*
-type Peer interface {
- GetID() []byte
- GetIDString() string
- GetAddressList() []*util.Address
- Sign(msg []byte) ([]byte, error)
- Verify(msg, sig []byte) bool
-}
-*/
+ "github.com/bfix/gospel/crypto/ed25519"
+)
+// Peer represents a node in the GNUnet P2P network.
type Peer struct {
- pub *ed25519.PublicKey
- idString string
- addrList []*util.Address
- prv *ed25519.PrivateKey // long-term signing key
+ prv *ed25519.PrivateKey // node private key (long-term
signing key)
+ pub *ed25519.PublicKey // node public key (=identifier)
+ idString string // node identifier as string
+ addrList []*util.Address // list of addresses associated with
node
ephPrv *ed25519.PrivateKey // ephemeral signing key
ephMsg *message.EphemeralKeyMsg // ephemeral signing key message
}
+// NewPeer instantiates a new peer object from given data. If a local peer
+// is created, the data is the seed for generating the private key of the node;
+// for a remote peer the data is the binary representation of its public key.
func NewPeer(data []byte, local bool) (p *Peer, err error) {
p = new(Peer)
if local {
@@ -45,42 +40,52 @@ func NewPeer(data []byte, local bool) (p *Peer, err error) {
return
}
+// EphKeyMsg returns a new initialized message to negotiate session keys.
func (p *Peer) EphKeyMsg() *message.EphemeralKeyMsg {
return p.ephMsg
}
+// SetEphKeyMsg saves a template for new key negotiation messages.
func (p *Peer) SetEphKeyMsg(msg *message.EphemeralKeyMsg) {
p.ephMsg = msg
}
+// EphPrvKey returns the current ephemeral private key.
func (p *Peer) EphPrvKey() *ed25519.PrivateKey {
return p.ephPrv
}
+// PrvKey return the private key of the node.
func (p *Peer) PrvKey() *ed25519.PrivateKey {
return p.prv
}
+// PubKey return the public key of the node.
func (p *Peer) PubKey() *ed25519.PublicKey {
return p.pub
}
+// GetID returns the node ID (public key) in binary format
func (p *Peer) GetID() []byte {
return p.pub.Bytes()
}
+// GetIDString returns the string representation of the public key of the node.
func (p *Peer) GetIDString() string {
return p.idString
}
+// GetAddressList returns a list of addresses associated with this peer.
func (p *Peer) GetAddressList() []*util.Address {
return p.addrList
}
+// AddAddress adds a new address for a node.
func (p *Peer) AddAddress(a *util.Address) {
p.addrList = append(p.addrList, a)
}
+// Sign a message with the (long-term) private key.
func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) {
if p.prv == nil {
return nil, fmt.Errorf("No private key")
@@ -88,6 +93,7 @@ func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error)
{
return p.prv.EdSign(msg)
}
+// Verify a message signature with the public key of a peer.
func (p *Peer) Verify(msg []byte, sig *ed25519.EdSignature) (bool, error) {
return p.pub.EdVerify(msg, sig)
}
diff --git a/src/gnunet/crypto/gns.go b/src/gnunet/crypto/gns.go
new file mode 100644
index 0000000..c6a8cd6
--- /dev/null
+++ b/src/gnunet/crypto/gns.go
@@ -0,0 +1,35 @@
+package crypto
+
+import (
+ "crypto/sha256"
+ "crypto/sha512"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+ "golang.org/x/crypto/hkdf"
+)
+
+// DeriveBlockKey returns a symmetric key and initialization vector to
decipher a GNS block.
+func DeriveBlockKey(label string, pub *ed25519.PublicKey) (iv *SymmetricIV,
skey *SymmetricKey) {
+ // generate symmetric key
+ prk := hkdf.Extract(sha512.New, pub.Bytes(), []byte("gns-aes-ctx-key"))
+ rdr := hkdf.Expand(sha256.New, prk, []byte(label))
+ skey = NewSymmetricKey()
+ rdr.Read(skey.AESKey)
+ rdr.Read(skey.TwofishKey)
+
+ // generate initialization vector
+ prk = hkdf.Extract(sha512.New, pub.Bytes(), []byte("gns-aes-ctx-iv"))
+ rdr = hkdf.Expand(sha256.New, prk, []byte(label))
+ iv = NewSymmetricIV()
+ rdr.Read(iv.AESIv)
+ rdr.Read(iv.TwofishIv)
+ return
+}
+
+// DecryptBlock for a given zone and label.
+func DecryptBlock(data []byte, zoneKey *ed25519.PublicKey, label string) (out
[]byte, err error) {
+ // derive key material for decryption
+ iv, skey := DeriveBlockKey(label, zoneKey)
+ // perform decryption
+ return SymmetricDecrypt(data, skey, iv)
+}
diff --git a/src/gnunet/crypto/gns_test.go b/src/gnunet/crypto/gns_test.go
new file mode 100644
index 0000000..7f3cdb8
--- /dev/null
+++ b/src/gnunet/crypto/gns_test.go
@@ -0,0 +1,150 @@
+package crypto
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+)
+
+var (
+ PUB = []byte{
+ 0x93, 0x34, 0x71, 0xF6, 0x99, 0x19, 0x0C, 0x62,
+ 0x85, 0xC7, 0x9B, 0x83, 0x9D, 0xCA, 0x83, 0x91,
+ 0x38, 0xFA, 0x87, 0xFB, 0xB8, 0xD4, 0xF6, 0xF0,
+ 0xF0, 0x4B, 0x7F, 0x0A, 0x48, 0xBF, 0x95, 0xF7,
+ }
+ LABEL = "home"
+)
+
+func TestDeriveBlockKey(t *testing.T) {
+ var (
+ SKEY = []byte{
+ 0x1D, 0x86, 0x8E, 0xF7, 0x30, 0x96, 0x3B, 0x39,
+ 0x66, 0xE6, 0x49, 0xD8, 0xF1, 0x13, 0x18, 0x39,
+ 0x8A, 0x7A, 0xB0, 0xF3, 0xDC, 0xF6, 0xE7, 0x2A,
+ 0xF6, 0x65, 0xDE, 0x86, 0x47, 0x7B, 0x20, 0x1B,
+
+ 0x21, 0xA6, 0xFA, 0x55, 0x7C, 0x29, 0xF5, 0x94,
+ 0x8E, 0x9A, 0x80, 0xB0, 0xB6, 0xD5, 0x4D, 0x38,
+ 0x0E, 0x6A, 0x0F, 0x42, 0x4B, 0x27, 0xBB, 0x6A,
+ 0x1E, 0xD1, 0x33, 0x08, 0xD6, 0x2E, 0x21, 0x8C,
+ }
+ IV = []byte{
+ 0xAC, 0x18, 0x03, 0xB7, 0x8B, 0x1E, 0x09, 0xA9,
+ 0xD0, 0x20, 0x47, 0x2B, 0x1B, 0x23, 0xE8, 0x24,
+
+ 0xC9, 0x23, 0x9E, 0x61, 0x3A, 0x8D, 0x95, 0xA9,
+ 0x3F, 0x6C, 0x1C, 0xC8, 0xCB, 0xD1, 0xBD, 0x6B,
+ }
+ )
+
+ iv, skey := DeriveBlockKey(LABEL, ed25519.NewPublicKeyFromBytes(PUB))
+
+ if bytes.Compare(IV[:16], iv.AESIv) != 0 {
+ t.Logf("AES_IV(computed) = %s\n", hex.EncodeToString(iv.AESIv))
+ t.Logf("AES_IV(expected) = %s\n", hex.EncodeToString(IV[:16]))
+ t.Fatal("AES IV mismatch")
+ }
+ if bytes.Compare(IV[16:], iv.TwofishIv) != 0 {
+ t.Logf("Twofish_IV(computed) = %s\n",
hex.EncodeToString(iv.TwofishIv))
+ t.Logf("Twofish_IV(expected) = %s\n",
hex.EncodeToString(IV[16:]))
+ t.Fatal("Twofish IV mismatch")
+ }
+
+ if bytes.Compare(SKEY[:32], skey.AESKey) != 0 {
+ t.Logf("AES_KEY(computed) = %s\n",
hex.EncodeToString(skey.AESKey))
+ t.Logf("AES_KEY(expected) = %s\n",
hex.EncodeToString(SKEY[:32]))
+ t.Fatal("AES KEY mismatch")
+ }
+ if bytes.Compare(SKEY[32:], skey.TwofishKey) != 0 {
+ t.Logf("Twofish_KEY(computed) = %s\n",
hex.EncodeToString(skey.TwofishKey))
+ t.Logf("Twofish_KEY(expected) = %s\n",
hex.EncodeToString(SKEY[32:]))
+ t.Fatal("Twofish KEY mismatch")
+ }
+}
+
+func TestDecryptBlock(t *testing.T) {
+ var (
+ DATA = []byte{
+ 0xAC, 0xA5, 0x3C, 0x55, 0x63, 0x21, 0x31, 0x1F,
+ 0x11, 0x6E, 0xEF, 0x48, 0xED, 0x53, 0x46, 0x31,
+ 0x7C, 0x50, 0xFB, 0x6B, 0xA6, 0xC8, 0x6C, 0x46,
+ 0x1E, 0xE3, 0xCA, 0x45, 0xCD, 0x5B, 0xD6, 0x86,
+ 0x42, 0x87, 0xEF, 0x18, 0xCE, 0x8E, 0x83, 0x21,
+ 0x04, 0xCB, 0xCF, 0x40, 0x7E, 0x0F, 0x51, 0x54,
+ 0xE2, 0x3C, 0xDE, 0xE9, 0x22, 0x00, 0xFF, 0x40,
+ 0xBB, 0x53, 0xE3, 0x69, 0x99, 0x92, 0x47, 0x97,
+ 0xF0, 0x4E, 0x3B, 0x70,
+ }
+ OUT = []byte{
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0xAD, 0x0E,
+ 0x60, 0x28, 0xFE, 0x80, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x0A, 0x68, 0x6F, 0x69, 0x2D, 0x70, 0x6F, 0x6C,
+ 0x6C, 0x6F, 0x69, 0x03, 0x6F, 0x72, 0x67, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ }
+ )
+
+ out, err := DecryptBlock(DATA, ed25519.NewPublicKeyFromBytes(PUB),
LABEL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes.Compare(out, OUT) != 0 {
+ t.Logf("Decrypt(computed) = %s\n", hex.EncodeToString(out))
+ t.Logf("Decrypt(expected) = %s\n", hex.EncodeToString(OUT))
+ t.Fatal("Decryptions failed")
+ }
+}
+
+func TestVerifyBlock(t *testing.T) {
+ var (
+ SIGNED = []byte{
+ 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0f,
+ 0x00, 0x05, 0xad, 0x0e, 0x60, 0x28, 0xfe, 0x80,
+ 0xac, 0xa5, 0x3c, 0x55, 0x63, 0x21, 0x31, 0x1f,
+ 0x11, 0x6e, 0xef, 0x48, 0xed, 0x53, 0x46, 0x31,
+ 0x7c, 0x50, 0xfb, 0x6b, 0xa6, 0xc8, 0x6c, 0x46,
+ 0x1e, 0xe3, 0xca, 0x45, 0xcd, 0x5b, 0xd6, 0x86,
+ 0x42, 0x87, 0xef, 0x18, 0xce, 0x8e, 0x83, 0x21,
+ 0x04, 0xcb, 0xcf, 0x40, 0x7e, 0x0f, 0x51, 0x54,
+ 0xe2, 0x3c, 0xde, 0xe9, 0x22, 0x00, 0xff, 0x40,
+ 0xbb, 0x53, 0xe3, 0x69, 0x99, 0x92, 0x47, 0x97,
+ 0xf0, 0x4e, 0x3b, 0x70,
+ }
+ SIG = []byte{
+ 0x09, 0xc9, 0x6a, 0xda, 0x69, 0xce, 0x7c, 0x91,
+ 0xbd, 0xa4, 0x59, 0xdc, 0xc9, 0x76, 0xf4, 0x6c,
+ 0x62, 0xb7, 0x79, 0x3f, 0x94, 0xb2, 0xf6, 0xf0,
+ 0x90, 0x17, 0x4e, 0x2f, 0x68, 0x49, 0xf8, 0xcc,
+
+ 0x0b, 0x77, 0x32, 0x32, 0x28, 0x77, 0x2d, 0x2a,
+ 0x31, 0x31, 0xc1, 0x2c, 0x44, 0x18, 0xf2, 0x5f,
+ 0x1a, 0xe9, 0x8b, 0x2e, 0x65, 0xca, 0x1d, 0xe8,
+ 0x22, 0x82, 0x6a, 0x06, 0xe0, 0x6a, 0x5a, 0xe5,
+ }
+ PUB = []byte{
+ 0x26, 0x84, 0x1b, 0x24, 0x35, 0xa4, 0x63, 0xe9,
+ 0xf0, 0x48, 0xae, 0x3e, 0xf7, 0xe8, 0x1b, 0xca,
+ 0x55, 0x9f, 0x4c, 0x1e, 0x16, 0x18, 0xa6, 0xd3,
+ 0x5b, 0x91, 0x0d, 0x54, 0x31, 0x6e, 0xbf, 0x97,
+ }
+ )
+ sig, err := ed25519.NewEcSignatureFromBytes(SIG)
+ if err != nil {
+ t.Fatal(err)
+ }
+ dkey := ed25519.NewPublicKeyFromBytes(PUB)
+ ok, err := dkey.EcVerify(SIGNED, sig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !ok {
+ t.Fatal("EcDSA verify failed")
+ }
+}
diff --git a/src/gnunet/crypto/hash.go b/src/gnunet/crypto/hash.go
index 87e3941..0fe7c7e 100644
--- a/src/gnunet/crypto/hash.go
+++ b/src/gnunet/crypto/hash.go
@@ -6,16 +6,19 @@ import (
"gnunet/util"
)
+// HashCode is the result of a 512-bit hash function (SHA-512)
type HashCode struct {
Bits []byte `size:"64"`
}
+// NewHashCode creates a new, uninitalized hash value
func NewHashCode() *HashCode {
return &HashCode{
Bits: make([]byte, 64),
}
}
+// Hash returns the SHA-512 hash value of a given blob
func Hash(data []byte) *HashCode {
val := sha512.Sum512(data)
return &HashCode{
diff --git a/src/gnunet/crypto/key_derivation.go
b/src/gnunet/crypto/key_derivation.go
index 575f511..976db2a 100644
--- a/src/gnunet/crypto/key_derivation.go
+++ b/src/gnunet/crypto/key_derivation.go
@@ -9,6 +9,7 @@ import (
"golang.org/x/crypto/hkdf"
)
+// Curve parameters
var (
ED25519_N = ed25519.GetCurve().N
)
diff --git a/src/gnunet/crypto/key_exchange.go
b/src/gnunet/crypto/key_exchange.go
index 0efa441..1403249 100644
--- a/src/gnunet/crypto/key_exchange.go
+++ b/src/gnunet/crypto/key_exchange.go
@@ -4,8 +4,8 @@ import (
"github.com/bfix/gospel/crypto/ed25519"
)
-// SharedSecret computes a 64 byte shared secret
-// between (prvA,pubB) and (prvB,pubA).
+// SharedSecret computes a 64 byte shared secret between (prvA,pubB)
+// and (prvB,pubA) by a Diffie-Hellman-like scheme.
func SharedSecret(prv *ed25519.PrivateKey, pub *ed25519.PublicKey) *HashCode {
ss := pub.Mult(prv.D).Q.X().Bytes()
return Hash(ss)
diff --git a/src/gnunet/crypto/signature.go b/src/gnunet/crypto/signature.go
index 9a69b56..ba8e535 100644
--- a/src/gnunet/crypto/signature.go
+++ b/src/gnunet/crypto/signature.go
@@ -1,5 +1,6 @@
package crypto
+// SignaturePurpose is the GNUnet data structure used as header for signed
data.
type SignaturePurpose struct {
Size uint32 `order:"big"` // How many bytes are signed?
Purpose uint32 `order:"big"` // Signature purpose
diff --git a/src/gnunet/crypto/symmetric.go b/src/gnunet/crypto/symmetric.go
index 82116a4..5607d3a 100644
--- a/src/gnunet/crypto/symmetric.go
+++ b/src/gnunet/crypto/symmetric.go
@@ -8,11 +8,17 @@ import (
"golang.org/x/crypto/twofish"
)
+// Symmetric encryption in GNUnet uses a two-layer scheme:
+// * Encryption: OUT = twofish_cfb(aes_cfb(IN))
+// * Decryption: OUT = aes_cfb(twofish_cfb(IN))
+
+// SymmetricKey is a key for the GNUnet-specific two-layer encryption scheme.
type SymmetricKey struct {
- AESKey []byte `size:"32"`
- TwofishKey []byte `size:"32"`
+ AESKey []byte `size:"32"` // key for AES-CFB
+ TwofishKey []byte `size:"32"` // key for Twofish-CFB
}
+// NewSymmetricKey generates a new (random) symmetric key.
func NewSymmetricKey() *SymmetricKey {
skey := &SymmetricKey{
AESKey: make([]byte, 32),
@@ -23,11 +29,14 @@ func NewSymmetricKey() *SymmetricKey {
return skey
}
+// SymmetricIV is an initialization vector for the GNUnet-specific two-layer
+// encryption scheme.
type SymmetricIV struct {
- AESIv []byte `size:"16"`
- TwofishIv []byte `size:"16"`
+ AESIv []byte `size:"16"` // IV for AES-CFB
+ TwofishIv []byte `size:"16"` // IV for Twofish-CFB
}
+// NewSymmetricIV generates a new (random) initialization vector.
func NewSymmetricIV() *SymmetricIV {
iv := &SymmetricIV{
AESIv: make([]byte, 16),
@@ -38,6 +47,7 @@ func NewSymmetricIV() *SymmetricIV {
return iv
}
+// SymmetricDecrypt decrypts the data with given key and initialization vector.
func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV)
([]byte, error) {
// Decrypt with Twofish CFB stream cipher
tf, err := twofish.NewCipher(skey.TwofishKey)
@@ -58,6 +68,7 @@ func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv
*SymmetricIV) ([]byte,
return out, nil
}
+// SymmetricEncrypt encrypts the data with given key and initialization vector.
func SymmetricEncrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV)
([]byte, error) {
// Encrypt with AES CFB stream cipher
aes, err := aes.NewCipher(skey.AESKey)
diff --git a/src/gnunet/enums/dht.go b/src/gnunet/enums/dht.go
index 87c36a3..8f004d7 100644
--- a/src/gnunet/enums/dht.go
+++ b/src/gnunet/enums/dht.go
@@ -1,5 +1,6 @@
package enums
+// DHT flags and settings
var (
DHT_RO_NONE = 0 // Default. Do nothing special.
DHT_RO_DEMULTIPLEX_EVERYWHERE = 1 // Each peer along the way should
look at 'enc'
@@ -10,3 +11,25 @@ var (
DHT_GNS_REPLICATION_LEVEL = 10
)
+
+// DHT block types
+var (
+ BLOCK_TYPE_ANY = 0 // Any type of block, used as a wildcard
when searching.
+ BLOCK_TYPE_FS_DBLOCK = 1 // Data block (leaf) in the CHK tree.
+ BLOCK_TYPE_FS_IBLOCK = 2 // Inner block in the CHK tree.
+ BLOCK_TYPE_FS_KBLOCK = 3 // Legacy type, no longer in use.
+ BLOCK_TYPE_FS_SBLOCK = 4 // Legacy type, no longer in use.
+ BLOCK_TYPE_FS_NBLOCK = 5 // Legacy type, no longer in use.
+ BLOCK_TYPE_FS_ONDEMAND = 6 // Type of a block representing a block
to be encoded on demand from disk.
+ BLOCK_TYPE_DHT_HELLO = 7 // Type of a block that contains a HELLO
for a peer
+ BLOCK_TYPE_TEST = 8 // Block for testing.
+ BLOCK_TYPE_FS_UBLOCK = 9 // Type of a block representing any type
of search result (universal).
+ BLOCK_TYPE_DNS = 10 // Block for storing DNS exit service
advertisements.
+ BLOCK_TYPE_GNS_NAMERECORD = 11 // Block for storing record data
+ BLOCK_TYPE_REVOCATION = 12 // Block type for a revocation message
by which a key is revoked.
+
+ BLOCK_TYPE_REGEX = 22 // Block to store a cadet regex state
+ BLOCK_TYPE_REGEX_ACCEPT = 23 // Block to store a cadet regex
accepting state
+ BLOCK_TYPE_SET_TEST = 24 // Block for testing set/consensus.
+ BLOCK_TYPE_CONSENSUS_ELEMENT = 25 // Block type for consensus elements.
+)
diff --git a/src/gnunet/enums/gns.go b/src/gnunet/enums/gns.go
index 2de5048..d5b1f7a 100644
--- a/src/gnunet/enums/gns.go
+++ b/src/gnunet/enums/gns.go
@@ -1,5 +1,6 @@
package enums
+// GNS constants
var (
GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be
stored in a GNS block.
diff --git a/src/gnunet/message/message.go b/src/gnunet/message/message.go
index 6b49a55..e792ae8 100644
--- a/src/gnunet/message/message.go
+++ b/src/gnunet/message/message.go
@@ -6,27 +6,35 @@ import (
"github.com/bfix/gospel/data"
)
+// Error codes
var (
ErrMsgHeaderTooSmall = errors.New("Message header too small")
)
+// Message is an interface for all GNUnet-specific messages.
type Message interface {
Header() *MessageHeader
}
+// MessageHeader encapsulates the common part of all GNUnet messages (at the
+// beginning of the data).
type MessageHeader struct {
MsgSize uint16 `order:"big"`
MsgType uint16 `order:"big"`
}
+// Size returns the total size of the message (header + body)
func (mh *MessageHeader) Size() uint16 {
return mh.MsgSize
}
+// Type returns the message type (defines the layout of the body data)
func (mh *MessageHeader) Type() uint16 {
return mh.MsgType
}
+// GetMsgHeader returns the header of a message from a byte array (as the
+// serialized form).
func GetMsgHeader(b []byte) (mh *MessageHeader, err error) {
if b == nil || len(b) < 4 {
return nil, ErrMsgHeaderTooSmall
diff --git a/src/gnunet/message/msg_core.go b/src/gnunet/message/msg_core.go
index 0ddbd8b..538fcea 100644
--- a/src/gnunet/message/msg_core.go
+++ b/src/gnunet/message/msg_core.go
@@ -5,21 +5,25 @@ import (
"fmt"
"time"
- "github.com/bfix/gospel/crypto/ed25519"
- "github.com/bfix/gospel/data"
+ "gnunet/crypto"
"gnunet/enums"
"gnunet/util"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+ "github.com/bfix/gospel/data"
)
+// EphKeyBlock defines the layout of signed ephemeral key with attributes.
type EphKeyBlock struct {
- SignSize uint32 `order:"big"` // length of signed block
- SigPurpose uint32 `order:"big"` // signature purpose:
SIG_ECC_KEY
- CreateTime util.AbsoluteTime // Time of key creation
- ExpireTime util.RelativeTime // Time to live for key
- EphemeralKey []byte `size:"32"` // Ephemeral EdDSA public key
- PeerID *util.PeerID // Peer identity (EdDSA public key)
+ Purpose *crypto.SignaturePurpose // signature purpose: SIG_ECC_KEY
+ CreateTime util.AbsoluteTime // Time of key creation
+ ExpireTime util.RelativeTime // Time to live for key
+ EphemeralKey []byte `size:"32"` // Ephemeral EdDSA
public key
+ PeerID *util.PeerID // Peer identity (EdDSA public
key)
}
+// EphemeralKeyMsg announces a new transient key for a peer. The key is signed
+// by the issuing peer.
type EphemeralKeyMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // CORE_EPHEMERAL_KEY (88)
@@ -28,6 +32,7 @@ type EphemeralKeyMsg struct {
SignedBlock *EphKeyBlock
}
+// NewEphemeralKeyMsg creates an empty message for key announcement.
func NewEphemeralKeyMsg() *EphemeralKeyMsg {
return &EphemeralKeyMsg{
MsgSize: 160,
@@ -35,8 +40,10 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg {
SenderStatus: 1,
Signature: make([]byte, 64),
SignedBlock: &EphKeyBlock{
- SignSize: 88,
- SigPurpose: enums.SIG_ECC_KEY,
+ Purpose: &crypto.SignaturePurpose{
+ Size: 88,
+ Purpose: enums.SIG_ECC_KEY,
+ },
CreateTime: util.AbsoluteTimeNow(),
ExpireTime: util.NewRelativeTime(12 * time.Hour),
EphemeralKey: make([]byte, 32),
@@ -45,6 +52,7 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *EphemeralKeyMsg) String() string {
return
fmt.Sprintf("EphKeyMsg{peer=%s,ephkey=%s,create=%s,expire=%s,status=%d}",
util.EncodeBinaryToString(m.SignedBlock.PeerID.Key),
@@ -58,10 +66,13 @@ func (msg *EphemeralKeyMsg) Header() *MessageHeader {
return &MessageHeader{msg.MsgSize, msg.MsgType}
}
+// Public extracts the public key of an announcing peer.
func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey {
return ed25519.NewPublicKeyFromBytes(m.SignedBlock.PeerID.Key)
}
+// Verify the integrity of the message data using the public key of the
+// announcing peer.
func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) {
data, err := data.Marshal(m.SignedBlock)
if err != nil {
@@ -74,6 +85,8 @@ func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey)
(bool, error) {
return pub.EdVerify(data, sig)
}
+// NewEphemeralKey creates a new ephemeral key signed by a long-term private
+// key and the corresponding GNUnet message to announce the new key.
func NewEphemeralKey(peerId []byte, ltPrv *ed25519.PrivateKey)
(*ed25519.PrivateKey, *EphemeralKeyMsg, error) {
msg := NewEphemeralKeyMsg()
copy(msg.SignedBlock.PeerID.Key, peerId)
diff --git a/src/gnunet/message/msg_dht.go b/src/gnunet/message/msg_dht.go
index bd3475a..b1d28ba 100644
--- a/src/gnunet/message/msg_dht.go
+++ b/src/gnunet/message/msg_dht.go
@@ -51,6 +51,7 @@ func (m *DHTClientGetMsg) SetXQuery(xq []byte) []byte {
return prev
}
+// String returns a human-readable representation of the message.
func (m *DHTClientGetMsg) String() string {
return
fmt.Sprintf("DHTClientGetMsg{Id:%d,Type=%d,Options=%d,Repl=%d,Key=%s}",
m.Id, m.Type, m.Options, m.ReplLevel,
hex.EncodeToString(m.Key.Bits))
@@ -98,6 +99,7 @@ func NewDHTClientResultMsg(key *crypto.HashCode)
*DHTClientResultMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *DHTClientResultMsg) String() string {
return fmt.Sprintf("DHTClientResultMsg{id:%d,expire=%s}", m.Id,
m.Expire)
}
diff --git a/src/gnunet/message/msg_gns.go b/src/gnunet/message/msg_gns.go
index 0ff34be..b01c410 100644
--- a/src/gnunet/message/msg_gns.go
+++ b/src/gnunet/message/msg_gns.go
@@ -3,9 +3,10 @@ package message
import (
"fmt"
- "github.com/bfix/gospel/logger"
"gnunet/enums"
"gnunet/util"
+
+ "github.com/bfix/gospel/logger"
)
//----------------------------------------------------------------------
@@ -38,13 +39,13 @@ func NewGNSLookupMsg() *GNSLookupMsg {
}
}
-// SetName
+// SetName appends the name to lookup to the message
func (m *GNSLookupMsg) SetName(name string) {
m.Name = util.Clone(append([]byte(name), 0))
m.MsgSize = uint16(48 + len(m.Name))
}
-// GetName
+// GetName returns the name to lookup from the message
func (m *GNSLookupMsg) GetName() string {
size := len(m.Name)
if m.Name[size-1] != 0 {
@@ -55,7 +56,7 @@ func (m *GNSLookupMsg) GetName() string {
return string(m.Name[:size])
}
-// String
+// String returns a human-readable representation of the message.
func (m *GNSLookupMsg) String() string {
return fmt.Sprintf(
"GNSLookupMsg{Id=%d,Zone=%s,Options=%d,Type=%d,Name=%s}",
@@ -72,6 +73,8 @@ func (msg *GNSLookupMsg) Header() *MessageHeader {
// GNS_LOOKUP_RESULT
//----------------------------------------------------------------------
+// GNSResourceRecord is the GNUnet-specific representation of resource
+// records (not to be confused with DNS resource records).
type GNSResourceRecord struct {
Expires util.AbsoluteTime // Expiration time for the record
Size uint32 `order:"big"` // Number of bytes in 'Data'
@@ -80,6 +83,7 @@ type GNSResourceRecord struct {
Data []byte `size:"Size"` // Record data
}
+// String returns a human-readable representation of the message.
func (r *GNSResourceRecord) String() string {
return
fmt.Sprintf("GNSResourceRecord{type=%s,expire=%s,flags=%d,size=%d}",
enums.GNS_TYPE[int(r.Type)], r.Expires, r.Flags, r.Size)
@@ -105,7 +109,7 @@ func NewGNSLookupResultMsg(id uint32) *GNSLookupResultMsg {
}
}
-// AddRecord
+// AddRecord adds a GNS resource recordto the response message.
func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error {
recSize := 20 + int(rec.Size)
if int(m.MsgSize)+recSize > enums.GNS_MAX_BLOCK_SIZE {
@@ -117,7 +121,7 @@ func (m *GNSLookupResultMsg) AddRecord(rec
*GNSResourceRecord) error {
return nil
}
-// String
+// String returns a human-readable representation of the message.
func (m *GNSLookupResultMsg) String() string {
return fmt.Sprintf("GNSLookupResultMsg{Id=%d,Count=%d}", m.Id, m.Count)
}
diff --git a/src/gnunet/message/msg_namecache.go
b/src/gnunet/message/msg_namecache.go
index 8f82622..9e3312d 100644
--- a/src/gnunet/message/msg_namecache.go
+++ b/src/gnunet/message/msg_namecache.go
@@ -33,7 +33,7 @@ func NewNamecacheLookupMsg(query *crypto.HashCode)
*NamecacheLookupMsg {
}
}
-// String
+// String returns a human-readable representation of the message.
func (m *NamecacheLookupMsg) String() string {
return fmt.Sprintf("NamecacheLookupMsg{Id=%d,Query=%s}",
m.Id, hex.EncodeToString(m.Query.Bits))
@@ -72,7 +72,7 @@ func NewNamecacheLookupResultMsg() *NamecacheLookupResultMsg {
}
}
-// String
+// String returns a human-readable representation of the message.
func (m *NamecacheLookupResultMsg) String() string {
return fmt.Sprintf("NamecacheLookupResultMsg{id=%d,expire=%s}",
m.Id, m.Expire)
diff --git a/src/gnunet/message/msg_transport.go
b/src/gnunet/message/msg_transport.go
index 1459d6a..54e63f2 100644
--- a/src/gnunet/message/msg_transport.go
+++ b/src/gnunet/message/msg_transport.go
@@ -4,22 +4,26 @@ import (
"fmt"
"time"
- "github.com/bfix/gospel/crypto/ed25519"
- "github.com/bfix/gospel/data"
+ "gnunet/crypto"
"gnunet/enums"
"gnunet/util"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+ "github.com/bfix/gospel/data"
)
//----------------------------------------------------------------------
// TRANSPORT_TCP_WELCOME
//----------------------------------------------------------------------
+// TransportTcpWelcomeMsg
type TransportTcpWelcomeMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // TRANSPORT_TCP_WELCOME (61)
PeerID *util.PeerID // Peer identity (EdDSA public key)
}
+// NewTransportTcpWelcomeMsg creates a new message for a given peer.
func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg {
if peerid == nil {
peerid = util.NewPeerID(nil)
@@ -31,6 +35,7 @@ func NewTransportTcpWelcomeMsg(peerid *util.PeerID)
*TransportTcpWelcomeMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *TransportTcpWelcomeMsg) String() string {
return fmt.Sprintf("TransportTcpWelcomeMsg{peer=%s}", m.PeerID)
}
@@ -40,6 +45,59 @@ func (msg *TransportTcpWelcomeMsg) Header() *MessageHeader {
return &MessageHeader{msg.MsgSize, msg.MsgType}
}
+//----------------------------------------------------------------------
+// TRANSPORT_PING
+//
+// Message used to ask a peer to validate receipt (to check an address
+// from a HELLO). Followed by the address we are trying to validate,
+// or an empty address if we are just sending a PING to confirm that a
+// connection which the receiver (of the PING) initiated is still valid.
+//----------------------------------------------------------------------
+
+// TransportPingMsg
+type TransportPingMsg struct {
+ MsgSize uint16 `order:"big"` // total size of message
+ MsgType uint16 `order:"big"` // TRANSPORT_PING (372)
+ Challenge uint32 // Challenge code (to ensure fresh reply)
+ Target *util.PeerID // EdDSA public key (long-term) of target peer
+ Address []byte `size:"*"` // encoded address
+}
+
+// TransportPingMsg creates a new message for given peer with an address to
+// be validated.
+func NewTransportPingMsg(target *util.PeerID, a *util.Address)
*TransportPingMsg {
+ if target == nil {
+ target = util.NewPeerID(nil)
+ }
+ m := &TransportPingMsg{
+ MsgSize: uint16(40),
+ MsgType: TRANSPORT_PING,
+ Challenge: util.RndUInt32(),
+ Target: target,
+ Address: nil,
+ }
+ if a != nil {
+ if addrData, err := data.Marshal(a); err == nil {
+ m.Address = addrData
+ m.MsgSize += uint16(len(addrData))
+ }
+ }
+ return m
+}
+
+// String returns a human-readable representation of the message.
+func (m *TransportPingMsg) String() string {
+ a := new(util.Address)
+ data.Unmarshal(a, m.Address)
+ return fmt.Sprintf("TransportPingMsg{target=%s,addr=%s,challenge=%d}",
+ m.Target, a, m.Challenge)
+}
+
+// Header returns the message header in a separate instance.
+func (msg *TransportPingMsg) Header() *MessageHeader {
+ return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
+
//----------------------------------------------------------------------
// TRANSPORT_PONG
//
@@ -53,29 +111,33 @@ func (msg *TransportTcpWelcomeMsg) Header() *MessageHeader
{
// a connection that we initiated).
//----------------------------------------------------------------------
+// SignedAddress is the signed block of data representing a node address
type SignedAddress struct {
- SignLength uint32 `order:"big"` // Length of signed block
- Purpose uint32 `order:"big"` // SIG_TRANSPORT_PONG_OWN
- ExpireOn util.AbsoluteTime // usec epoch
- AddrSize uint32 `order:"big"` // size of address
- Address []byte `size:"AddrSize"` // address
+ Purpose *crypto.SignaturePurpose // SIG_TRANSPORT_PONG_OWN
+ ExpireOn util.AbsoluteTime // usec epoch
+ AddrSize uint32 `order:"big"` // size of address
+ Address []byte `size:"AddrSize"` // address
}
+// NewSignedAddress creates a new (signable) data block from an address.
func NewSignedAddress(a *util.Address) *SignedAddress {
// serialize address
addrData, _ := data.Marshal(a)
alen := len(addrData)
addr := &SignedAddress{
- SignLength: uint32(alen + 20),
- Purpose: enums.SIG_TRANSPORT_PONG_OWN,
- ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour),
- AddrSize: uint32(alen),
- Address: make([]byte, alen),
+ Purpose: &crypto.SignaturePurpose{
+ Size: uint32(alen + 20),
+ Purpose: enums.SIG_TRANSPORT_PONG_OWN,
+ },
+ ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour),
+ AddrSize: uint32(alen),
+ Address: make([]byte, alen),
}
copy(addr.Address, addrData)
return addr
}
+// TransportPongMsg
type TransportPongMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // TRANSPORT_PING (372)
@@ -84,6 +146,8 @@ type TransportPongMsg struct {
SignedBlock *SignedAddress // signed block of data
}
+// NewTransportPongMsg creates a reponse message with an address the replying
+// peer wants to be reached.
func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg {
m := &TransportPongMsg{
MsgSize: 72,
@@ -94,12 +158,13 @@ func NewTransportPongMsg(challenge uint32, a
*util.Address) *TransportPongMsg {
}
if a != nil {
sa := NewSignedAddress(a)
- m.MsgSize += uint16(sa.SignLength)
+ m.MsgSize += uint16(sa.Purpose.Size)
m.SignedBlock = sa
}
return m
}
+// String returns a human-readable representation of the message.
func (m *TransportPongMsg) String() string {
a := new(util.Address)
if err := data.Unmarshal(a, m.SignedBlock.Address); err == nil {
@@ -114,6 +179,7 @@ func (msg *TransportPongMsg) Header() *MessageHeader {
return &MessageHeader{msg.MsgSize, msg.MsgType}
}
+// Sign the address block of a pong message.
func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error {
data, err := data.Marshal(m.SignedBlock)
if err != nil {
@@ -127,6 +193,7 @@ func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey)
error {
return nil
}
+// Verify the address block of a pong message
func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) {
data, err := data.Marshal(m.SignedBlock)
if err != nil {
@@ -139,55 +206,6 @@ func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey)
(bool, error) {
return pub.EdVerify(data, sig)
}
-//----------------------------------------------------------------------
-// TRANSPORT_PING
-//
-// Message used to ask a peer to validate receipt (to check an address
-// from a HELLO). Followed by the address we are trying to validate,
-// or an empty address if we are just sending a PING to confirm that a
-// connection which the receiver (of the PING) initiated is still valid.
-//----------------------------------------------------------------------
-
-type TransportPingMsg struct {
- MsgSize uint16 `order:"big"` // total size of message
- MsgType uint16 `order:"big"` // TRANSPORT_PING (372)
- Challenge uint32 // Challenge code (to ensure fresh reply)
- Target *util.PeerID // EdDSA public key (long-term) of target peer
- Address []byte `size:"*"` // encoded address
-}
-
-func NewTransportPingMsg(target *util.PeerID, a *util.Address)
*TransportPingMsg {
- if target == nil {
- target = util.NewPeerID(nil)
- }
- m := &TransportPingMsg{
- MsgSize: uint16(40),
- MsgType: TRANSPORT_PING,
- Challenge: util.RndUInt32(),
- Target: target,
- Address: nil,
- }
- if a != nil {
- if addrData, err := data.Marshal(a); err == nil {
- m.Address = addrData
- m.MsgSize += uint16(len(addrData))
- }
- }
- return m
-}
-
-func (m *TransportPingMsg) String() string {
- a := new(util.Address)
- data.Unmarshal(a, m.Address)
- return fmt.Sprintf("TransportPingMsg{target=%s,addr=%s,challenge=%d}",
- m.Target, a, m.Challenge)
-}
-
-// Header returns the message header in a separate instance.
-func (msg *TransportPingMsg) Header() *MessageHeader {
- return &MessageHeader{msg.MsgSize, msg.MsgType}
-}
-
//----------------------------------------------------------------------
// HELLO
//
@@ -202,6 +220,7 @@ func (msg *TransportPingMsg) Header() *MessageHeader {
// 4) address (address-length bytes)
//----------------------------------------------------------------------
+// HelloAddress
type HelloAddress struct {
Transport string // Name of transport
AddrSize uint16 `order:"big"` // Size of address entry
@@ -209,6 +228,7 @@ type HelloAddress struct {
Address []byte `size:"AddrSize"` // Address specification
}
+// NewHelloAddress create a new HELLO address from the given address
func NewAddress(a *util.Address) *HelloAddress {
addr := &HelloAddress{
Transport: a.Transport,
@@ -220,11 +240,13 @@ func NewAddress(a *util.Address) *HelloAddress {
return addr
}
+// String returns a human-readable representation of the message.
func (a *HelloAddress) String() string {
return fmt.Sprintf("Address{%s,expire=%s}",
util.AddressString(a.Transport, a.Address), a.ExpireOn)
}
+// HelloMsg
type HelloMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // HELLO (17)
@@ -233,6 +255,7 @@ type HelloMsg struct {
Addresses []*HelloAddress `size:"*"` // List of end-point addressess
}
+// NewHelloMsg creates a new HELLO msg for a given peer.
func NewHelloMsg(peerid *util.PeerID) *HelloMsg {
if peerid == nil {
peerid = util.NewPeerID(nil)
@@ -246,11 +269,13 @@ func NewHelloMsg(peerid *util.PeerID) *HelloMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *HelloMsg) String() string {
return fmt.Sprintf("HelloMsg{peer=%s,friendsonly=%d,addr=%v}",
m.PeerID, m.FriendOnly, m.Addresses)
}
+// AddAddress adds a new address to the HELLO message.
func (m *HelloMsg) AddAddress(a *HelloAddress) {
m.Addresses = append(m.Addresses, a)
m.MsgSize += uint16(len(a.Transport)) + a.AddrSize + 11
@@ -265,11 +290,13 @@ func (msg *HelloMsg) Header() *MessageHeader {
// TRANSPORT_SESSION_ACK
//----------------------------------------------------------------------
+// SessionAckMsg
type SessionAckMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // TRANSPORT_SESSION_ACK (377)
}
+// NewSessionAckMsg creates an new message (no body required).
func NewSessionAckMsg() *SessionAckMsg {
return &SessionAckMsg{
MsgSize: 16,
@@ -277,6 +304,7 @@ func NewSessionAckMsg() *SessionAckMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *SessionAckMsg) String() string {
return "SessionAck{}"
}
@@ -290,6 +318,7 @@ func (msg *SessionAckMsg) Header() *MessageHeader {
// TRANSPORT_SESSION_SYN
//----------------------------------------------------------------------
+// SessionSynMsg
type SessionSynMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN (375)
@@ -297,6 +326,7 @@ type SessionSynMsg struct {
Timestamp util.AbsoluteTime // usec epoch
}
+// NewSessionSynMsg creates a SYN request for the a session
func NewSessionSynMsg() *SessionSynMsg {
return &SessionSynMsg{
MsgSize: 16,
@@ -306,6 +336,7 @@ func NewSessionSynMsg() *SessionSynMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *SessionSynMsg) String() string {
return fmt.Sprintf("SessionSyn{timestamp=%s}", m.Timestamp)
}
@@ -319,6 +350,7 @@ func (msg *SessionSynMsg) Header() *MessageHeader {
// TRANSPORT_SESSION_SYN_ACK
//----------------------------------------------------------------------
+// SessionSynAckMsg
type SessionSynAckMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN_ACK
(376)
@@ -326,6 +358,7 @@ type SessionSynAckMsg struct {
Timestamp util.AbsoluteTime // usec epoch
}
+// NewSessionSynAckMsg is an ACK for a SYN request
func NewSessionSynAckMsg() *SessionSynAckMsg {
return &SessionSynAckMsg{
MsgSize: 16,
@@ -335,6 +368,7 @@ func NewSessionSynAckMsg() *SessionSynAckMsg {
}
}
+// String returns a human-readable representation of the message.
func (m *SessionSynAckMsg) String() string {
return fmt.Sprintf("SessionSynAck{timestamp=%s}", m.Timestamp)
}
@@ -348,12 +382,14 @@ func (msg *SessionSynAckMsg) Header() *MessageHeader {
// TRANSPORT_SESSION_QUOTA
//----------------------------------------------------------------------
+// SessionQuotaMsg
type SessionQuotaMsg struct {
MsgSize uint16 `order:"big"` // total size of message
MsgType uint16 `order:"big"` // TRANSPORT_SESSION_QUOTA (379)
Quota uint32 `order:"big"` // Quota in bytes per second
}
+// NewSessionQuotaMsg announces a session quota to the other end of the
session.
func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg {
m := new(SessionQuotaMsg)
if quota > 0 {
@@ -364,6 +400,7 @@ func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg {
return m
}
+// String returns a human-readable representation of the message.
func (m *SessionQuotaMsg) String() string {
return fmt.Sprintf("SessionQuotaMsg{%sB/s}",
util.Scale1024(uint64(m.Quota)))
}
@@ -374,57 +411,63 @@ func (msg *SessionQuotaMsg) Header() *MessageHeader {
}
//----------------------------------------------------------------------
-// TRANSPORT_SESSION_KEEPALIVE_RESPONSE
+// TRANSPORT_SESSION_KEEPALIVE
//----------------------------------------------------------------------
-type SessionKeepAliveRespMsg struct {
+// SessionKeepAliveMsg
+type SessionKeepAliveMsg struct {
MsgSize uint16 `order:"big"` // total size of message
- MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE_RESPONSE
(382)
+ MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE (381)
Nonce uint32
}
-func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg {
- m := &SessionKeepAliveRespMsg{
+// NewSessionKeepAliveMsg creates a new request to keep a session.
+func NewSessionKeepAliveMsg() *SessionKeepAliveMsg {
+ m := &SessionKeepAliveMsg{
MsgSize: 8,
- MsgType: TRANSPORT_SESSION_KEEPALIVE_RESPONSE,
- Nonce: nonce,
+ MsgType: TRANSPORT_SESSION_KEEPALIVE,
+ Nonce: util.RndUInt32(),
}
return m
}
-func (m *SessionKeepAliveRespMsg) String() string {
- return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce)
+// String returns a human-readable representation of the message.
+func (m *SessionKeepAliveMsg) String() string {
+ return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce)
}
// Header returns the message header in a separate instance.
-func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader {
+func (msg *SessionKeepAliveMsg) Header() *MessageHeader {
return &MessageHeader{msg.MsgSize, msg.MsgType}
}
//----------------------------------------------------------------------
-// TRANSPORT_SESSION_KEEPALIVE
+// TRANSPORT_SESSION_KEEPALIVE_RESPONSE
//----------------------------------------------------------------------
-type SessionKeepAliveMsg struct {
+// SessionKeepAliveRespMsg
+type SessionKeepAliveRespMsg struct {
MsgSize uint16 `order:"big"` // total size of message
- MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE (381)
+ MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE_RESPONSE
(382)
Nonce uint32
}
-func NewSessionKeepAliveMsg() *SessionKeepAliveMsg {
- m := &SessionKeepAliveMsg{
+// NewSessionKeepAliveRespMsg is a response message for a "keep session"
request.
+func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg {
+ m := &SessionKeepAliveRespMsg{
MsgSize: 8,
- MsgType: TRANSPORT_SESSION_KEEPALIVE,
- Nonce: util.RndUInt32(),
+ MsgType: TRANSPORT_SESSION_KEEPALIVE_RESPONSE,
+ Nonce: nonce,
}
return m
}
-func (m *SessionKeepAliveMsg) String() string {
- return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce)
+// String returns a human-readable representation of the message.
+func (m *SessionKeepAliveRespMsg) String() string {
+ return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce)
}
// Header returns the message header in a separate instance.
-func (msg *SessionKeepAliveMsg) Header() *MessageHeader {
+func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader {
return &MessageHeader{msg.MsgSize, msg.MsgType}
}
diff --git a/src/gnunet/service/client.go b/src/gnunet/service/client.go
index 2d1c3dd..3bae7da 100644
--- a/src/gnunet/service/client.go
+++ b/src/gnunet/service/client.go
@@ -1,9 +1,10 @@
package service
import (
- "github.com/bfix/gospel/logger"
"gnunet/message"
"gnunet/transport"
+
+ "github.com/bfix/gospel/logger"
)
// Client
diff --git a/src/gnunet/service/gns/block.go b/src/gnunet/service/gns/block.go
new file mode 100644
index 0000000..9d83f99
--- /dev/null
+++ b/src/gnunet/service/gns/block.go
@@ -0,0 +1,185 @@
+package gns
+
+import (
+ "fmt"
+
+ "gnunet/crypto"
+ "gnunet/enums"
+ "gnunet/message"
+ "gnunet/util"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+ "github.com/bfix/gospel/data"
+)
+
+var (
+ ErrBlockNotDecrypted = fmt.Errorf("GNS block not decrypted")
+)
+
+//======================================================================
+// GNS block: An encrypted and signed container for GNS resource records
+// that represents the "atomic" data structure associated with a GNS
+// label in a given zone.
+//======================================================================
+
+// SignedBlockData: signed and encrypted list of resource records stored
+// in a GNSRecordSet
+type SignedBlockData struct {
+ Purpose *crypto.SignaturePurpose // Size and purpose of signature (8
bytes)
+ Expire util.AbsoluteTime // Expiration time of the block.
+ EncData []byte `size:"*"` // encrypted GNSRecordSet
+
+ // transient data (not serialized)
+ data []byte // unencrypted GNSRecord set
+}
+
+// GNSBlock is the result of GNS lookups for a given label in a zone.
+type GNSBlock struct {
+ Signature []byte `size:"64"` // Signature of the block.
+ DerivedKey []byte `size:"32"` // Derived key used for signing
+ Block *SignedBlockData
+
+ // transient data (not serialized)
+ checked bool // block integrity checked
+ verified bool // block signature verified (internal)
+ decrypted bool // block data decrypted (internal)
+}
+
+// String returns the human-readable representation of a GNSBlock
+func (b *GNSBlock) String() string {
+ return fmt.Sprintf("GNSBlock{Verified=%v,Decrypted=%v,data=[%d]}",
+ b.verified, b.decrypted, len(b.Block.EncData))
+}
+
+// Records returns the list of resource records in a block.
+func (b *GNSBlock) Records() ([]*message.GNSResourceRecord, error) {
+ // check if block is decrypted
+ if !b.decrypted {
+ return nil, ErrBlockNotDecrypted
+ }
+ // parse block data into record set
+ rs := NewGNSRecordSet()
+ if err := data.Unmarshal(rs, b.Block.data); err != nil {
+ return nil, err
+ }
+ return rs.Records, nil
+}
+
+// Verify the integrity of the block data from a signature.
+func (b *GNSBlock) Verify(zoneKey *ed25519.PublicKey, label string) (err
error) {
+ // Integrity check performed
+ b.checked = true
+
+ // verify derived key
+ dkey := ed25519.NewPublicKeyFromBytes(b.DerivedKey)
+ dkey2 := crypto.DerivePublicKey(zoneKey, label, "gns")
+ if !dkey.Q.Equals(dkey2.Q) {
+ return fmt.Errorf("Invalid signature key for GNS Block")
+ }
+ // verify signature
+ var (
+ sig *ed25519.EcSignature
+ buf []byte
+ ok bool
+ )
+ if sig, err = ed25519.NewEcSignatureFromBytes(b.Signature); err != nil {
+ return
+ }
+ if buf, err = data.Marshal(b.Block); err != nil {
+ return
+ }
+ if ok, err = dkey.EcVerify(buf, sig); err == nil && !ok {
+ err = fmt.Errorf("Signature verification failed for GNS block")
+ }
+ b.verified = true
+ return
+}
+
+// Decrypt block data with a key/iv combination derived from (PKEY,label)
+func (b *GNSBlock) Decrypt(zoneKey *ed25519.PublicKey, label string) (err
error) {
+ // decrypt payload
+ b.Block.data, err = crypto.DecryptBlock(b.Block.EncData, zoneKey, label)
+ b.decrypted = true
+ return
+}
+
+// NewGNSBlock instantiates an empty GNS block
+func NewGNSBlock() *GNSBlock {
+ return &GNSBlock{
+ Signature: make([]byte, 64),
+ DerivedKey: make([]byte, 32),
+ Block: &SignedBlockData{
+ Purpose: new(crypto.SignaturePurpose),
+ Expire: *new(util.AbsoluteTime),
+ EncData: nil,
+ data: nil,
+ },
+ checked: false,
+ verified: false,
+ decrypted: false,
+ }
+}
+
+//----------------------------------------------------------------------
+// GNSRecordSet
+//----------------------------------------------------------------------
+
+// GNSRecordSet ist the GNUnet data structure for a list of resource records
+// in a GNSBlock. As part of GNUnet messages, the record set is padded so that
+// the binary size of (records||padding) is the smallest power of two.
+type GNSRecordSet struct {
+ Count uint32 `order:"big"` // number of
resource records
+ Records []*message.GNSResourceRecord `size:"Count"` // list of resource
records
+ Padding []byte `size:"*"` // padding
+}
+
+// NewGNSRecordSet returns an empty resource record set.
+func NewGNSRecordSet() *GNSRecordSet {
+ return &GNSRecordSet{
+ Count: 0,
+ Records: make([]*message.GNSResourceRecord, 0),
+ Padding: make([]byte, 0),
+ }
+}
+
+// AddRecord to append a resource record to the set.
+func (rs *GNSRecordSet) AddRecord(rec *message.GNSResourceRecord) {
+ rs.Count++
+ rs.Records = append(rs.Records, rec)
+}
+
+//======================================================================
+// List of resource records types (for GNS/DNS queries)
+//======================================================================
+
+// RRTypeList is a list of integers representing RR types.
+type RRTypeList []int
+
+// Initialize a new type list with given type values
+func NewRRTypeList(args ...int) (res RRTypeList) {
+ for _, val := range args {
+ // if GNS_TYPE_ANY is encountered, it becomes the sole type
+ if val == enums.GNS_TYPE_ANY {
+ res = make(RRTypeList, 1)
+ res[0] = val
+ return
+ }
+ res = append(res, val)
+ }
+ return
+}
+
+// HasType returns true if the type is included in the list
+func (tl RRTypeList) HasType(t int) bool {
+ // return true if type is GNS_TYPE_ANY
+ if tl[0] == enums.GNS_TYPE_ANY {
+ return true
+ }
+ // check for type in list
+ for _, val := range tl {
+ if val == t {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/gnunet/service/gns/block_handler.go
b/src/gnunet/service/gns/block_handler.go
new file mode 100644
index 0000000..860b4a7
--- /dev/null
+++ b/src/gnunet/service/gns/block_handler.go
@@ -0,0 +1,398 @@
+package gns
+
+import (
+ "encoding/hex"
+ "fmt"
+
+ "gnunet/enums"
+ "gnunet/message"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+ "github.com/bfix/gospel/logger"
+)
+
+// HdlrInst is the type for functions that instanciate custom block handlers.
+type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error)
+
+// Error codes
+var (
+ ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block")
+ ErrBlockHandler = fmt.Errorf("Internal block handler failure")
+)
+
+// Mapping of RR types to BlockHandler instanciation functions
+var (
+ customHandler = map[int]HdlrInst{
+ enums.GNS_TYPE_PKEY: NewPkeyHandler,
+ enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler,
+ enums.GNS_TYPE_BOX: NewBoxHandler,
+ enums.GNS_TYPE_LEHO: NewLehoHandler,
+ }
+)
+
+//======================================================================
+// GNS blocks that contain special records (PKEY, GNS2DNS, BOX, LEHO...)
+// require special treatment with respect to other resource records with
+// different types in the same block. Usually only certain other types
+// (or none at all) are allowed.
+//======================================================================
+
+// BlockHandler interface.
+type BlockHandler interface {
+ // AddRecord inserts a RR into the BlockHandler for (later) processing.
+ // The handler can inspect the remaining labels in a path if required.
+ // It returns an error if a record is not accepted by the block handler.
+ AddRecord(rr *message.GNSResourceRecord, labels []string) error
+
+ // TypeAction returns a flag indicating how a resource record of a
+ // given type is to be treated by a custom block handler:
+ // = -1: Record is not allowed
+ // = 0: Record is allowed but will be ignored
+ // = 1: Record is allowed and will be processed
+ TypeAction(t int) int
+
+ // Records returns a list of RR of the given types associated with
+ // the custom handler
+ Records(kind RRTypeList) *GNSRecordSet
+}
+
+//----------------------------------------------------------------------
+// Manage list of block handlers
+// Under normal circumstances there is only one (or none) block handler
+// per block, but future constructs may allow multiple block handlers
+// to be present. The block handler list implements the BlockHandler
+// interface.
+// The BlockHandlerList maintains a map of actually instantiated handlers
+// (indexed by record type) and a list of record types (with occurrence
+// count) in the block.
+//----------------------------------------------------------------------
+
+// BlockHandlerList is a list of block handlers instantiated.
+type BlockHandlerList struct {
+ list map[int]BlockHandler // list of handler instances
+}
+
+// NewBlockHandlerList instantiates an a list of active block handlers
+// for a given set of records (GNS block).
+func NewBlockHandlerList(records []*message.GNSResourceRecord, labels
[]string) (*BlockHandlerList, error) {
+ // initialize block handler list
+ hl := &BlockHandlerList{
+ list: make(map[int]BlockHandler),
+ }
+ // build a list of record types that are handled by a custom handler.
+ rrList := NewRRTypeList(
+ enums.GNS_TYPE_PKEY,
+ enums.GNS_TYPE_GNS2DNS,
+ enums.GNS_TYPE_BOX,
+ enums.GNS_TYPE_LEHO)
+
+ // Traverse record list and build list of handler instances
+ for _, rec := range records {
+ // check for custom handler type
+ rrType := int(rec.Type)
+ if rrList.HasType(rrType) {
+ // check if a handler for given type already exists
+ var (
+ hdlr BlockHandler
+ ok bool
+ err error
+ )
+ if hdlr, ok = hl.list[rrType]; ok {
+ // add record to existing handler
+ if err = hdlr.AddRecord(rec, labels); err !=
nil {
+ return nil, err
+ }
+ continue
+ }
+ // create a new handler instance
+ switch rrType {
+ case enums.GNS_TYPE_PKEY:
+ hdlr, err = NewPkeyHandler(rec, labels)
+ case enums.GNS_TYPE_GNS2DNS:
+ hdlr, err = NewGns2DnsHandler(rec, labels)
+ case enums.GNS_TYPE_BOX:
+ hdlr, err = NewBoxHandler(rec, labels)
+ case enums.GNS_TYPE_LEHO:
+ hdlr, err = NewLehoHandler(rec, labels)
+ }
+ if err != nil {
+ return nil, err
+ }
+ // store handler in list
+ hl.list[rrType] = hdlr
+ }
+ }
+ return hl, nil
+}
+
+// GetHandler returns a BlockHandler for the given key. If no block handler
exists
+// under the given name, a new one is created and stored in the list. The type
of
+// the new block handler is derived from the key value.
+func (hl *BlockHandlerList) GetHandler(t int) BlockHandler {
+ // return handler for given key if it exists
+ if hdlr, ok := hl.list[t]; ok {
+ return hdlr
+ }
+ return nil
+}
+
+//----------------------------------------------------------------------
+// PKEY handler: Only one PKEY as sole record in a block
+//----------------------------------------------------------------------
+
+// PkeyHandler implementing the BlockHandler interface
+type PkeyHandler struct {
+ pkey *ed25519.PublicKey // Zone key
+ rec *message.GNSResourceRecord // associated recource record
+}
+
+// NewPkeyHandler returns a new BlockHandler instance
+func NewPkeyHandler(rec *message.GNSResourceRecord, labels []string)
(BlockHandler, error) {
+ if int(rec.Type) != enums.GNS_TYPE_PKEY {
+ return nil, ErrInvalidRecordType
+ }
+ h := &PkeyHandler{
+ pkey: nil,
+ }
+ if err := h.AddRecord(rec, labels); err != nil {
+ return nil, err
+ }
+ return h, nil
+}
+
+// AddRecord inserts a PKEY record into the handler.
+func (h *PkeyHandler) AddRecord(rec *message.GNSResourceRecord, labels
[]string) error {
+ if int(rec.Type) != enums.GNS_TYPE_PKEY {
+ return ErrInvalidRecordType
+ }
+ // check for sole PKEY record in block
+ if h.pkey != nil {
+ return ErrInvalidPKEY
+ }
+ // check for sane key data
+ if len(rec.Data) != 32 {
+ return ErrInvalidPKEY
+ }
+ // set a PKEY handler
+ h.pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
+ h.rec = rec
+ return nil
+}
+
+// TypeAction return a flag indicating how a resource record of a given type
+// is to be treated (see BlockHandler interface)
+func (h *PkeyHandler) TypeAction(t int) int {
+ // no other resource record type is not allowed
+ if t == enums.GNS_TYPE_PKEY {
+ return 1
+ }
+ return -1
+}
+
+// Records returns a list of RR of the given type associated with this handler
+func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet {
+ rs := NewGNSRecordSet()
+ if kind.HasType(enums.GNS_TYPE_PKEY) {
+ rs.AddRecord(h.rec)
+ }
+ return rs
+}
+
+//----------------------------------------------------------------------
+// GNS2DNS handler
+//----------------------------------------------------------------------
+
+// Gns2DnsHandler implementing the BlockHandler interface
+type Gns2DnsHandler struct {
+ Name string // DNS query name
+ Servers []string // DNS servers to ask
+ recs []*message.GNSResourceRecord // list of rersource records
+}
+
+// NewGns2DnsHandler returns a new BlockHandler instance
+func NewGns2DnsHandler(rec *message.GNSResourceRecord, labels []string)
(BlockHandler, error) {
+ if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
+ return nil, ErrInvalidRecordType
+ }
+ h := &Gns2DnsHandler{
+ Name: "",
+ Servers: make([]string, 0),
+ recs: make([]*message.GNSResourceRecord, 0),
+ }
+ if err := h.AddRecord(rec, labels); err != nil {
+ return nil, err
+ }
+ return h, nil
+}
+
+// AddRecord inserts a GNS2DNS record into the handler.
+func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels
[]string) error {
+ if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
+ return ErrInvalidRecordType
+ }
+ logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n",
hex.EncodeToString(rec.Data))
+
+ // extract list of names in DATA block:
+ next, dnsQuery := DNSNameFromBytes(rec.Data, 0)
+ dnsServer := string(rec.Data[next : len(rec.Data)-1])
+ logger.Printf(logger.DBG, "[gns] GNS2DNS query '%s'@'%s'\n", dnsQuery,
dnsServer)
+ if len(dnsServer) == 0 || len(dnsQuery) == 0 {
+ return ErrInvalidRecordBody
+ }
+
+ // check if all GNS2DNS records refer to the same query name
+ if len(h.Servers) == 0 {
+ h.Name = dnsQuery
+ }
+ if dnsQuery != h.Name {
+ return ErrInvalidRecordBody
+ }
+ h.Servers = append(h.Servers, dnsServer)
+ h.recs = append(h.recs, rec)
+ return nil
+}
+
+// TypeAction return a flag indicating how a resource record of a given type
+// is to be treated (see BlockHandler interface)
+func (h *Gns2DnsHandler) TypeAction(t int) int {
+ // anything goes...
+ return 1
+}
+
+// Records returns a list of RR of the given type associated with this handler
+func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet {
+ rs := NewGNSRecordSet()
+ if kind.HasType(enums.GNS_TYPE_GNS2DNS) {
+ for _, rec := range h.recs {
+ rs.AddRecord(rec)
+ }
+ }
+ return rs
+}
+
+//----------------------------------------------------------------------
+// BOX handler
+//----------------------------------------------------------------------
+
+// BoxHandler implementing the BlockHandler interface
+type BoxHandler struct {
+ boxes map[string]*Box // map of found boxes
+}
+
+// NewBoxHandler returns a new BlockHandler instance
+func NewBoxHandler(rec *message.GNSResourceRecord, labels []string)
(BlockHandler, error) {
+ if int(rec.Type) != enums.GNS_TYPE_BOX {
+ return nil, ErrInvalidRecordType
+ }
+ h := &BoxHandler{
+ boxes: make(map[string]*Box),
+ }
+ if err := h.AddRecord(rec, labels); err != nil {
+ return nil, err
+ }
+ return h, nil
+}
+
+// AddRecord inserts a BOX record into the handler.
+func (h *BoxHandler) AddRecord(rec *message.GNSResourceRecord, labels
[]string) error {
+ if int(rec.Type) != enums.GNS_TYPE_BOX {
+ return ErrInvalidRecordType
+ }
+ logger.Printf(logger.DBG, "[box-rr] for labels %v\n", labels)
+ // check if we need to process the BOX record:
+ // (1) only two remaining labels
+ if len(labels) != 2 {
+ return nil
+ }
+ // (2) remaining labels must start with '_'
+ if labels[0][0] != '_' || labels[1][0] != '_' {
+ return nil
+ }
+ // (3) check of "svc" and "proto" match values in the BOX
+ box := NewBox(rec)
+ if box.Matches(labels) {
+ logger.Println(logger.DBG, "[box-rr] MATCH -- adding record")
+ h.boxes[box.key] = box
+ }
+ return nil
+}
+
+// TypeAction return a flag indicating how a resource record of a given type
+// is to be treated (see BlockHandler interface)
+func (h *BoxHandler) TypeAction(t int) int {
+ // anything goes...
+ return 1
+}
+
+// Records returns a list of RR of the given type associated with this handler
+func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet {
+ rs := NewGNSRecordSet()
+ for _, box := range h.boxes {
+ if kind.HasType(int(box.Type)) {
+ // valid box found: assemble new resource record.
+ rr := new(message.GNSResourceRecord)
+ rr.Expires = box.rec.Expires
+ rr.Flags = box.rec.Flags
+ rr.Type = box.Type
+ rr.Size = uint32(len(box.RR))
+ rr.Data = box.RR
+ rs.AddRecord(rr)
+ }
+ }
+ return rs
+}
+
+//----------------------------------------------------------------------
+// LEHO handler
+//----------------------------------------------------------------------
+
+// LehoHandler implementing the BlockHandler interface
+type LehoHandler struct {
+ name string
+ rec *message.GNSResourceRecord
+}
+
+// NewLehoHandler returns a new BlockHandler instance
+func NewLehoHandler(rec *message.GNSResourceRecord, labels []string)
(BlockHandler, error) {
+ if int(rec.Type) != enums.GNS_TYPE_LEHO {
+ return nil, ErrInvalidRecordType
+ }
+ h := &LehoHandler{
+ name: "",
+ }
+ if err := h.AddRecord(rec, labels); err != nil {
+ return nil, err
+ }
+ return h, nil
+}
+
+// AddRecord inserts a LEHO record into the handler.
+func (h *LehoHandler) AddRecord(rec *message.GNSResourceRecord, labels
[]string) error {
+ if int(rec.Type) != enums.GNS_TYPE_LEHO {
+ return ErrInvalidRecordType
+ }
+ h.name = string(rec.Data)
+ h.rec = rec
+ return nil
+}
+
+// TypeAction return a flag indicating how a resource record of a given type
+// is to be treated (see BlockHandler interface)
+func (h *LehoHandler) TypeAction(t int) int {
+ // only A and AAAA records allowed beside LEHO
+ switch t {
+ case enums.GNS_TYPE_LEHO, enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA:
+ return 1
+ default:
+ return -1
+ }
+}
+
+// Records returns a list of RR of the given type associated with this handler
+func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet {
+ rs := NewGNSRecordSet()
+ if kind.HasType(enums.GNS_TYPE_LEHO) {
+ rs.AddRecord(h.rec)
+ }
+ return rs
+}
diff --git a/src/gnunet/service/gns/box.go b/src/gnunet/service/gns/box.go
new file mode 100644
index 0000000..e2d3609
--- /dev/null
+++ b/src/gnunet/service/gns/box.go
@@ -0,0 +1,151 @@
+package gns
+
+import (
+ "encoding/hex"
+ "strconv"
+ "strings"
+
+ "gnunet/message"
+
+ "github.com/bfix/gospel/data"
+ "github.com/bfix/gospel/logger"
+)
+
+// Box is an encapsulated RR for special names
+type Box struct {
+ Proto uint16 `order:"big"` // Protcol identifier
+ Svc uint16 `order:"big"` // Service identifier
+ Type uint32 `order:"big"` // Type of embedded RR
+ RR []byte `size:"*"` // embedded RR
+
+ // transient attributes (not serialized)
+ key string // map key for box instance
+ rec *message.GNSResourceRecord // originating RR
+}
+
+// NewBox creates a new box instance from a BOX resource record.
+func NewBox(rec *message.GNSResourceRecord) *Box {
+ b := new(Box)
+ if err := data.Unmarshal(b, rec.Data); err != nil {
+ logger.Printf(logger.ERROR, "[gns] Can't unmarshal BOX")
+ return nil
+ }
+ b.key = hex.EncodeToString(rec.Data[:8])
+ b.rec = rec
+ return b
+}
+
+// Matches verifies that the remaining labels comply with the values
+// in the BOX record.
+func (b *Box) Matches(labels []string) bool {
+ // resolve protocol and service names
+ proto, protoName := GetProtocol(labels[0])
+ svc, _ := GetService(labels[1], protoName)
+ // no match on invalid resolution
+ if proto == 0 || svc == 0 {
+ return false
+ }
+ // check for matching values in box
+ return proto == b.Proto && svc == b.Svc
+}
+
+//----------------------------------------------------------------------
+// helper functions
+
+// list of handled protocols in BOX records
+var protocols = map[string]int{
+ "icmp": 1,
+ "igmp": 2,
+ "tcp": 6,
+ "udp": 17,
+ "ipv6-icmp": 58,
+}
+
+// GetProtocol returns the protocol number and name for a given name. The
+// name can be an integer value (e.g. "_6" for "tcp") or a mnemonic name
+// (e.g. like "_tcp").
+func GetProtocol(name string) (uint16, string) {
+ // check for required prefix
+ if name[0] != '_' {
+ return 0, ""
+ }
+ name = strings.ToLower(name[1:])
+
+ // if label is an integer value it is the protocol number
+ if val, err := strconv.Atoi(name); err == nil {
+ // check for valid number (reverse protocol lookup)
+ for label, id := range protocols {
+ if id == val {
+ // return found entry
+ return uint16(val), label
+ }
+ }
+ // number out of range
+ return 0, ""
+ }
+ // try to resolve via protocol map
+ if id, ok := protocols[name]; ok {
+ return uint16(id), name
+ }
+ // resolution failed
+ return 0, ""
+}
+
+// list of services (per protocol) handled in BOX records
+var services = map[string]map[string]int{
+ "udp": {
+ "domain": 53,
+ },
+ "tcp": {
+ "ftp": 21,
+ "ftps": 990,
+ "gopher": 70,
+ "http": 80,
+ "https": 443,
+ "imap2": 143,
+ "imap3": 220,
+ "imaps": 993,
+ "pop3": 110,
+ "pop3s": 995,
+ "smtp": 25,
+ "ssh": 22,
+ "telnet": 23,
+ },
+}
+
+// GetService returns the port number and the name of a service (with given
+// protocol). The name can be an integer value (e.g. "_443" for "https") or
+// a mnemonic name (e.g. like "_https").
+func GetService(name, proto string) (uint16, string) {
+ // check for required prefix
+ if name[0] != '_' {
+ return 0, ""
+ }
+ name = strings.ToLower(name[1:])
+
+ // get list of services for given protocol
+ svcs, ok := services[proto]
+ if !ok {
+ // no services available for this protocol
+ return 0, ""
+ }
+
+ // if label is an integer value it is the port number
+ if val, err := strconv.Atoi(name); err == nil {
+ // check for valid number (reverse service lookup)
+ for label, id := range svcs {
+ if id == val {
+ // return found entry
+ return uint16(val), label
+ }
+ }
+ // number out of range
+ return 0, ""
+ }
+ // try to resolve via services map
+ if id, ok := svcs[name]; ok {
+ return uint16(id), name
+ }
+ // resolution failed
+ return 0, ""
+}
diff --git a/src/gnunet/service/gns/dns.go b/src/gnunet/service/gns/dns.go
index 2ebe331..fe138b0 100644
--- a/src/gnunet/service/gns/dns.go
+++ b/src/gnunet/service/gns/dns.go
@@ -47,7 +47,7 @@ func DNSNameFromBytes(b []byte, offset int) (int, string) {
// queryDNS resolves a name on a given nameserver and delivers all matching
// resource record (of type 'kind') to the result channel.
-func queryDNS(id int, name string, server net.IP, kind int, res chan
*GNSRecordSet) {
+func queryDNS(id int, name string, server net.IP, kind RRTypeList, res chan
*GNSRecordSet) {
logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on
'%s'...\n", id, name, server.String())
// assemble query
@@ -91,27 +91,32 @@ func queryDNS(id int, name string, server net.IP, kind int,
res chan *GNSRecordS
}
set := NewGNSRecordSet()
for _, record := range in.Answer {
- // create a new GNS resource record
- rr := new(message.GNSResourceRecord)
- rr.Expires = util.AbsoluteTimeNever()
- rr.Flags = 0
- rr.Type = uint32(record.Header().Rrtype)
- rr.Size = uint32(record.Header().Rdlength)
- rr.Data = make([]byte, rr.Size)
+ // check if answer record is of requested type
+ if kind.HasType(int(record.Header().Rrtype)) {
+ // get wire-format of resource record
+ buf := make([]byte, 2048)
+ n, err := dns.PackRR(record, buf, 0, nil, false)
+ if err != nil {
+ logger.Printf(logger.WARN, "[dns][%d]
Failed to get RR data for %s\n", id, err.Error())
+ continue
+ }
- // get wire-format of resource record
- buf := make([]byte, 2048)
- n, err := dns.PackRR(record, buf, 0, nil, false)
- if err != nil {
- logger.Printf(logger.WARN, "[dns][%d] Failed to
get RR data for %s\n", id, err.Error())
- continue
- }
- if n < int(rr.Size) {
- logger.Printf(logger.WARN, "[dns][%d] Nit
enough data in RR (%d != %d)\n", id, n, rr.Size)
- continue
+ // create a new GNS resource record
+ rr := new(message.GNSResourceRecord)
+ expires :=
time.Now().Add(time.Duration(record.Header().Ttl) * time.Second)
+ rr.Expires = util.NewAbsoluteTime(expires)
+ rr.Flags = 0
+ rr.Type = uint32(record.Header().Rrtype)
+ rr.Size = uint32(record.Header().Rdlength)
+ rr.Data = make([]byte, rr.Size)
+
+ if n < int(rr.Size) {
+ logger.Printf(logger.WARN, "[dns][%d]
Not enough data in RR (%d != %d)\n", id, n, rr.Size)
+ continue
+ }
+ copy(rr.Data, buf[n-int(rr.Size):])
+ set.AddRecord(rr)
}
- copy(rr.Data, buf[n-int(rr.Size):])
- set.AddRecord(rr)
}
logger.Printf(logger.WARN, "[dns][%d] %d resource records
extracted from response (%d/5).\n", id, set.Count, retry+1)
res <- set
@@ -124,7 +129,7 @@ func queryDNS(id int, name string, server net.IP, kind int,
res chan *GNSRecordS
// ResolveDNS resolves a name in DNS. Multiple DNS servers are queried in
// parallel; the first result delivered by any of the servers is returned
// as the result list of matching resource records.
-func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey
*ed25519.PublicKey) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) ResolveDNS(name string, servers []string, kind
RRTypeList, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) {
logger.Printf(logger.DBG, "[dns] Resolution of '%s' starting...\n",
name)
// start DNS queries concurrently
@@ -133,20 +138,22 @@ func (gns *GNSModule) ResolveDNS(name string, servers
[]string, kind int, pkey *
for idx, srv := range servers {
// check if srv is an IPv4/IPv6 address
addr := net.ParseIP(srv)
+ logger.Printf(logger.DBG, "ParseIP('%s', len=%d) --> %v\n",
srv, len(srv), addr)
if addr == nil {
+ query := NewRRTypeList(enums.GNS_TYPE_DNS_A,
enums.GNS_TYPE_DNS_AAAA)
// no; resolve server name in GNS
if strings.HasSuffix(srv, ".+") {
// resolve server name relative to current zone
zone := util.EncodeBinaryToString(pkey.Bytes())
srv = strings.TrimSuffix(srv, ".+")
- set, err = gns.Resolve(srv, pkey,
enums.GNS_TYPE_ANY, enums.GNS_LO_DEFAULT)
+ set, err = gns.Resolve(srv, pkey, query,
enums.GNS_LO_DEFAULT)
if err != nil {
logger.Printf(logger.ERROR, "[dns]
Can't resolve NS server '%s' in '%s'\n", srv, zone)
continue
}
} else {
- // resolve absolute GNS name (MUST end in a
PKEY)
- set, err = gns.Resolve(srv, nil,
enums.GNS_TYPE_ANY, enums.GNS_LO_DEFAULT)
+ // resolve absolute GNS name (name MUST end in
a PKEY)
+ set, err = gns.Resolve(srv, nil, query,
enums.GNS_LO_DEFAULT)
if err != nil {
logger.Printf(logger.ERROR, "[dns]
Can't resolve NS server '%s'\n", srv)
continue
@@ -158,11 +165,17 @@ func (gns *GNSModule) ResolveDNS(name string, servers
[]string, kind int, pkey *
switch int(rec.Type) {
case enums.GNS_TYPE_DNS_AAAA:
addr = net.IP(rec.Data)
+ // we prefer IPv6
break rec_loop
case enums.GNS_TYPE_DNS_A:
addr = net.IP(rec.Data)
}
}
+ // check if we have an IP address available
+ if addr == nil {
+ logger.Printf(logger.WARN, "[dns] No IP address
for nameserver in GNS")
+ continue
+ }
}
// query DNS concurrently
go queryDNS(idx, name, addr, kind, res)
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go
index e4dc5fb..3e7bd18 100644
--- a/src/gnunet/service/gns/module.go
+++ b/src/gnunet/service/gns/module.go
@@ -1,7 +1,6 @@
package gns
import (
- "encoding/hex"
"fmt"
"strings"
@@ -54,83 +53,40 @@ func NewQuery(pkey *ed25519.PublicKey, label string) *Query
{
}
}
-//----------------------------------------------------------------------
-// GNS blocks with special types (PKEY, GNS2DNS) require special
-// treatment with respect to other resource records with different types
-// in the same block. Usually only certain other types (or not at all)
-// are allowed and the allowed ones are required to deliver a consistent
-// list of resulting resource records passed back to the caller.
-//----------------------------------------------------------------------
-
-// BlockHandler interface.
-type BlockHandler interface {
- // TypeAction returns a flag indicating how a resource record of a
- // given type is to be treated:
- // = -1: Record is not allowed (terminates lookup with an error)
- // = 0: Record is allowed but will be ignored
- // = 1: Record is allowed and will be processed
- TypeAction(int) int
-}
-
-// Gns2DnsHandler implementing the BlockHandler interface
-type Gns2DnsHandler struct {
- Name string
- Servers []string
-}
-
-// NewGns2DnsHandler returns a new BlockHandler instance
-func NewGns2DnsHandler() *Gns2DnsHandler {
- return &Gns2DnsHandler{
- Name: "",
- Servers: make([]string, 0),
- }
-}
-
-// TypeAction return a flag indicating how a resource record of a given type
-// is to be treated (see RecordMaster interface)
-func (m *Gns2DnsHandler) TypeAction(t int) int {
- // only process other GNS2DNS records
- if t == enums.GNS_TYPE_GNS2DNS {
- return 1
- }
- // skip everything else
- return 0
-}
-
-// AddRequest adds the DNS request for "name" at "server" to the list
-// of requests. All GNS2DNS records must query for the same name
-func (m *Gns2DnsHandler) AddRequest(name, server string) bool {
- if len(m.Servers) == 0 {
- m.Name = name
- }
- if name != m.Name {
- return false
- }
- m.Servers = append(m.Servers, server)
- return true
-}
-
//----------------------------------------------------------------------
// The GNS module (recursively) resolves GNS names:
-// Resolves DNS-like names (e.g. "minecraft.servers.bob.games") to the
-// requested resource records (RRs). In short, the resolution process
-// works as follows:
+// Resolves DNS-like names (e.g. "minecraft.servers.bob.games"; a name is
+// a list of labels with '.' as separator) to the requested resource
+// records (RRs). In short, the resolution process works as follows:
//
// Resolve(name):
// --------------
-// (1) split the full name into elements in reverse order: names[]
-// (2) Resolve first element (root zone, right-most name part, name[0]) to
+// (1) split the name ('.' as separator) into labels in reverse order:
labels[]
+// (2) Resolve first label (= root zone, right-most name part, labels[0]) to
// a zone public key PKEY:
-// (a) the name is a string representation of a public key -> (3)
-// (b) the zone key for the name is stored in the config file -> (3)
-// (c) a local zone with that given name -> (3)
+// (a) the label is a string representation of a public key -> (3)
+// (b) the zone key for the label is stored in the config file -> (3)
+// (c) a local zone with that given label -> (3)
// (d) ERROR: "Unknown root zone"
-// (3) names = names[1:] // remove first element
-// block = Lookup (PKEY, names[0]):
-// (a) If last element of namess: -> (4)
-// (b) block is PKEY record:
-// PKEY <- block, --> (3)
-// (4) return block: it is the responsibility of the caller to assemble
+// (3) labels = labels[1:]
+// records = Resolve (labels[0], PKEY)
+// If last label in name: -> (5)
+// (4) for all rec in records:
+// (a) if rec is a PKEY record:
+// PKEY <- record, --> (3)
+// (b) if rec is a GNS2DNS record:
+// delegate to DNS to resolve rest of name -> (5)
+// (c) if rec is BOX record:
+// if rest of name is pattern "_service._proto" and matches
+// the values in the BOX:
+// Replace records with resource record from BOX -> (5)
+// (d) if rec is CNAME record:
+// if no remaining labels:
+// if requested types include CNAME -> (5)
+// if
+// resolution failed: name not completely processed and no zone available
+//
+// (5) return records: it is the responsibility of the caller to assemble
// the desired result from block data (e.g. filter for requested
// resource record types).
//----------------------------------------------------------------------
@@ -145,10 +101,10 @@ type GNSModule struct {
GetLocalZone func(name string) (*ed25519.PublicKey, error)
}
-// Resolve a GNS name with multiple elements, If pkey is not nil, the name
+// Resolve a GNS name with multiple labels. If pkey is not nil, the name
// is interpreted as "relative to current zone".
-func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int,
mode int) (set *GNSRecordSet, err error) {
- // get the name elements in reverse order
+func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind
RRTypeList, mode int) (set *GNSRecordSet, err error) {
+ // get the labels in reverse order
names := util.ReverseStringList(strings.Split(path, "."))
logger.Printf(logger.DBG, "[gns] Resolver called for %v\n", names)
@@ -161,8 +117,8 @@ func (gns *GNSModule) Resolve(path string, pkey
*ed25519.PublicKey, kind int, mo
return gns.ResolveAbsolute(names, kind, mode)
}
-// Resolve a fully qualified GNS absolute name (with multiple levels).
-func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set
*GNSRecordSet, err error) {
+// Resolve a fully qualified GNS absolute name (with multiple labels).
+func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode
int) (set *GNSRecordSet, err error) {
// get the root zone key for the TLD
var (
pkey *ed25519.PublicKey
@@ -170,40 +126,43 @@ func (gns *GNSModule) ResolveAbsolute(names []string,
kind int, mode int) (set *
)
for {
// (1) check if TLD is a public key string
- if len(names[0]) == 52 {
- if data, err = util.DecodeStringToBinary(names[0], 32);
err == nil {
+ if len(labels[0]) == 52 {
+ if data, err = util.DecodeStringToBinary(labels[0],
32); err == nil {
if pkey = ed25519.NewPublicKeyFromBytes(data);
pkey != nil {
break
}
}
}
// (2) check if TLD is in our local config
- if pkey = config.Cfg.GNS.GetRootZoneKey(names[0]); pkey != nil {
+ if pkey = config.Cfg.GNS.GetRootZoneKey(labels[0]); pkey != nil
{
break
}
// (3) check if TLD is one of our identities
- if pkey, err = gns.GetLocalZone(names[0]); err == nil {
+ if pkey, err = gns.GetLocalZone(labels[0]); err == nil {
break
}
// (4) we can't resolve this TLD
return nil, ErrUnknownTLD
}
// continue with resolution relative to a zone.
- return gns.ResolveRelative(names[1:], pkey, kind, mode)
+ return gns.ResolveRelative(labels[1:], pkey, kind, mode)
}
// Resolve relative path (to a given zone) recursively by processing simple
// (PKEY,Label) lookups in sequence and handle intermediate GNS record types
-func (gns *GNSModule) ResolveRelative(names []string, pkey *ed25519.PublicKey,
kind int, mode int) (set *GNSRecordSet, err error) {
+func (gns *GNSModule) ResolveRelative(labels []string, pkey
*ed25519.PublicKey, kind RRTypeList, mode int) (set *GNSRecordSet, err error) {
// Process all names in sequence
- var records []*message.GNSResourceRecord
+ var (
+ records []*message.GNSResourceRecord // final resource records
from resolution
+ hdlrs *BlockHandlerList // list of block handlers
in final step
+ )
name_loop:
- for ; len(names) > 0; names = names[1:] {
- logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in
'%s'\n", names[0], util.EncodeBinaryToString(pkey.Bytes()))
+ for ; len(labels) > 0; labels = labels[1:] {
+ logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in
'%s'\n", labels[0], util.EncodeBinaryToString(pkey.Bytes()))
// resolve next level
var block *GNSBlock
- if block, err = gns.Lookup(pkey, names[0], mode ==
enums.GNS_LO_DEFAULT); err != nil {
+ if block, err = gns.Lookup(pkey, labels[0], mode ==
enums.GNS_LO_DEFAULT); err != nil {
// failed to resolve name
return
}
@@ -213,94 +172,64 @@ name_loop:
}
// post-process block by inspecting contained resource records
for
// special GNS types
- var hdlr BlockHandler
if records, err = block.Records(); err != nil {
return
}
- for _, rec := range records {
- // let a block handler decide how to handle records
- if hdlr != nil {
- switch hdlr.TypeAction(int(rec.Type)) {
- case -1:
- // No records of this type allowed in
block
- err = ErrInvalidRecordType
- return
- case 0:
- // records of this type are simply
ignored
- continue
- case 1:
- // process record of this type
- }
- }
- switch int(rec.Type) {
-
//----------------------------------------------------------
- case enums.GNS_TYPE_PKEY:
- // check for single RR and sane key data
- if len(rec.Data) != 32 || len(records) > 1 {
- err = ErrInvalidPKEY
- return
- }
- // set new PKEY and continue resolution
- pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
- continue name_loop
+ // assemble a list of block handlers for this block: if multiple
+ // block handlers are present, they are consistent with all
block
+ // records.
+ if hdlrs, err = NewBlockHandlerList(records, labels[1:]); err
!= nil {
+ // conflicting block handler records found: terminate
with error.
+ // (N.B.: The BlockHandlerList class executes the logic
which mix
+ // of resource records in a single block is considered
valid.)
+ return
+ }
-
//----------------------------------------------------------
- case enums.GNS_TYPE_GNS2DNS:
- // get the master controlling this block;
create a new
- // one if necessary
- var inst *Gns2DnsHandler
- if hdlr == nil {
- inst = NewGns2DnsHandler()
- hdlr = inst
- } else {
- inst = hdlr.(*Gns2DnsHandler)
- }
- // extract list of names in DATA block:
- logger.Printf(logger.DBG, "[gns] GNS2DNS data:
%s\n", hex.EncodeToString(rec.Data))
- var dnsNames []string
- for pos := 0; ; {
- next, name :=
DNSNameFromBytes(rec.Data, pos)
- if len(name) == 0 {
- break
- }
- dnsNames = append(dnsNames, name)
- pos = next
- }
- logger.Printf(logger.DBG, "[gns] GNS2DNS
params: %v\n", dnsNames)
- if len(dnsNames) != 2 {
- err = ErrInvalidRecordBody
- return
- }
- // Add to collection of requests
- logger.Printf(logger.DBG, "[gns] GNS2DNS: query
for '%s' on '%s'\n", dnsNames[0], dnsNames[1])
- if !inst.AddRequest(dnsNames[0], dnsNames[1]) {
- err = ErrInvalidRecordBody
- return
- }
+ //--------------------------------------------------------------
+ // handle special block cases in priority order:
+ //--------------------------------------------------------------
+
+ if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_PKEY); hdlr != nil {
+ // (1) PKEY record:
+ inst := hdlr.(*PkeyHandler)
+ // if labels are pending, set new zone and continue
resolution
+ if len(labels) > 1 {
+ pkey = inst.pkey
+ continue name_loop
}
- }
- // handle special block cases
- if hdlr != nil {
- switch inst := hdlr.(type) {
- case *Gns2DnsHandler:
- // we need to handle delegation to DNS: returns
a list of found
- // resource records in DNS (filter by 'kind')
- fqdn :=
strings.Join(util.ReverseStringList(names[1:]), ".") + "." + inst.Name
- if set, err = gns.ResolveDNS(fqdn,
inst.Servers, kind, pkey); err != nil {
- logger.Println(logger.ERROR, "[gns]
GNS2DNS resilution failed.")
- return
- }
- // we are done with resolution; pass on records
to caller
- records = set.Records
+ } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_GNS2DNS);
hdlr != nil {
+ // (2) GNS2DNS records: delegate resolution to DNS
+ inst := hdlr.(*Gns2DnsHandler)
+ // we need to handle delegation to DNS: returns a list
of found
+ // resource records in DNS (filter by 'kind')
+ lbls :=
strings.Join(util.ReverseStringList(labels[1:]), ".")
+ if len(lbls) > 0 {
+ lbls += "."
+ }
+ fqdn := lbls + inst.Name
+ if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind,
pkey); err != nil {
+ logger.Println(logger.ERROR, "[gns] GNS2DNS
resolution failed.")
+ return
+ }
+ // we are done with resolution; pass on records to
caller
+ records = set.Records
+ break name_loop
+ } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_BOX); hdlr !=
nil {
+ // (3) BOX records:
+ inst := hdlr.(*BoxHandler)
+ new_records := inst.Records(kind).Records
+ if len(new_records) > 0 {
+ records = new_records
break name_loop
}
}
}
- // Assemble resulting resource record set
+ // Assemble resulting resource record set by filtering for requested
types.
+ // Records might get transformed by active block handlers.
set = NewGNSRecordSet()
for _, rec := range records {
// is this the record type we are looking for?
- if kind == enums.GNS_TYPE_ANY || int(rec.Type) == kind {
+ if kind.HasType(int(rec.Type)) {
// add it to the result
set.AddRecord(rec)
}
@@ -321,7 +250,6 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label
string, remote bool)
return
}
if block == nil {
- logger.Println(logger.DBG, "[gns] local Lookup: no block found")
if remote {
// get the block from a remote lookup
if block, err = gns.LookupRemote(query); err != nil ||
block == nil {
@@ -330,12 +258,15 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey,
label string, remote bool)
block = nil
} else {
logger.Println(logger.DBG, "[gns]
remote Lookup: no block found")
+ err = fmt.Errorf("No block found")
}
// lookup fails completely -- no result
return
}
// store RRs from remote locally.
gns.StoreLocal(query, block)
+ } else {
+ err = fmt.Errorf("No block found")
}
}
return
diff --git a/src/gnunet/service/gns/service.go
b/src/gnunet/service/gns/service.go
index 852f513..dd516ff 100644
--- a/src/gnunet/service/gns/service.go
+++ b/src/gnunet/service/gns/service.go
@@ -4,9 +4,6 @@ import (
"encoding/hex"
"io"
- "github.com/bfix/gospel/crypto/ed25519"
- "github.com/bfix/gospel/data"
- "github.com/bfix/gospel/logger"
"gnunet/config"
"gnunet/crypto"
"gnunet/enums"
@@ -14,6 +11,10 @@ import (
"gnunet/service"
"gnunet/transport"
"gnunet/util"
+
+ "github.com/bfix/gospel/crypto/ed25519"
+ "github.com/bfix/gospel/data"
+ "github.com/bfix/gospel/logger"
)
//----------------------------------------------------------------------
@@ -77,7 +78,8 @@ func (s *GNSService) ServeClient(mc *transport.MsgChannel) {
// access to the message channel to send
responses)
pkey := ed25519.NewPublicKeyFromBytes(m.Zone)
label := m.GetName()
- recset, err := s.Resolve(label, pkey, int(m.Type),
int(m.Options))
+ kind := NewRRTypeList(int(m.Type))
+ recset, err := s.Resolve(label, pkey, kind,
int(m.Options))
if err != nil {
logger.Printf(logger.ERROR, "[gns] Failed to
lookup block: %s\n", err.Error())
break
@@ -146,7 +148,7 @@ func (s *GNSService) LookupNamecache(query *Query) (block
*GNSBlock, err error)
break
}
// check if block was found
- if len(m.EncData) == 0 {
+ if len(m.EncData) == 0 || util.IsNull(m.EncData) {
logger.Println(logger.DBG, "[gns] block not found in
namecache")
break
}
diff --git a/src/gnunet/service/service.go b/src/gnunet/service/service.go
index 5b44d47..6aab226 100644
--- a/src/gnunet/service/service.go
+++ b/src/gnunet/service/service.go
@@ -3,8 +3,9 @@ package service
import (
"fmt"
- "github.com/bfix/gospel/logger"
"gnunet/transport"
+
+ "github.com/bfix/gospel/logger"
)
// Service is an interface for GNUnet services. Every service has one channel
@@ -48,7 +49,7 @@ func (si *ServiceImpl) Start(spec string) (err error) {
}
// start channel server
- logger.Printf(logger.DBG, "[%s] Service starting.\n", si.name)
+ logger.Printf(logger.INFO, "[%s] Service starting.\n", si.name)
if si.srvc, err = transport.NewChannelServer(spec, si.hdlr); err != nil
{
return
}
@@ -61,19 +62,19 @@ func (si *ServiceImpl) Start(spec string) (err error) {
select {
case in := <-si.hdlr:
if in == nil {
- logger.Printf(logger.DBG, "[%s]
Listener terminated.\n", si.name)
+ logger.Printf(logger.INFO, "[%s]
Listener terminated.\n", si.name)
break loop
}
switch ch := in.(type) {
case transport.Channel:
- logger.Printf(logger.DBG, "[%s] Client
connected.\n", si.name)
+ logger.Printf(logger.INFO, "[%s] Client
connected.\n", si.name)
go
si.impl.ServeClient(transport.NewMsgChannel(ch))
}
case <-si.ctrl:
break loop
}
}
- logger.Printf(logger.DBG, "[%s] Service closing.\n", si.name)
+ logger.Printf(logger.INFO, "[%s] Service closing.\n", si.name)
si.srvc.Close()
si.running = false
}()
@@ -89,7 +90,7 @@ func (si *ServiceImpl) Stop() error {
}
si.running = false
si.ctrl <- true
- logger.Printf(logger.DBG, "[%s] Service terminating.\n", si.name)
+ logger.Printf(logger.INFO, "[%s] Service terminating.\n", si.name)
return si.impl.Stop()
}
diff --git a/src/gnunet/transport/channel.go b/src/gnunet/transport/channel.go
index 8502d8f..4005759 100644
--- a/src/gnunet/transport/channel.go
+++ b/src/gnunet/transport/channel.go
@@ -11,6 +11,7 @@ import (
"gnunet/message"
)
+// Error codes
var (
ErrChannelNotImplemented = fmt.Errorf("Protocol not implemented")
ErrChannelNotOpened = fmt.Errorf("Channel not opened")
diff --git a/src/gnunet/transport/channel_netw.go
b/src/gnunet/transport/channel_netw.go
index 69ddda5..ecfd8e2 100644
--- a/src/gnunet/transport/channel_netw.go
+++ b/src/gnunet/transport/channel_netw.go
@@ -14,11 +14,12 @@ import (
// NetworkChannel
type NetworkChannel struct {
- network string
- conn net.Conn
+ network string // network protocol identifier ("tcp", "unix", ...)
+ conn net.Conn // associated connection
}
-// NewNetworkChannel
+// NewNetworkChannel creates a new channel for a given network protocol.
+// The channel is in pending state and need to be opened before use.
func NewNetworkChannel(netw string) Channel {
return &NetworkChannel{
network: netw,
@@ -26,7 +27,11 @@ func NewNetworkChannel(netw string) Channel {
}
}
-// Open
+// Open a network channel based on specification:
+// The specification is a string separated into parts by the '+' delimiter
+// (e.g. "unix+/tmp/gnunet-service-gns-go.sock+perm=0770"). The network
+// identifier (first part) must match the network specification of the
+// underlaying NetworkChannel instance.
func (c *NetworkChannel) Open(spec string) (err error) {
parts := strings.Split(spec, "+")
// check for correct protocol
@@ -38,7 +43,7 @@ func (c *NetworkChannel) Open(spec string) (err error) {
return
}
-// Close
+// Close a network channel
func (c *NetworkChannel) Close() error {
if c.conn != nil {
return c.conn.Close()
@@ -46,7 +51,8 @@ func (c *NetworkChannel) Close() error {
return ErrChannelNotOpened
}
-// Read
+// Read bytes from a network channel into buffer: Returns the number of read
+// bytes and an error code. Only works on open channels ;)
func (c *NetworkChannel) Read(buf []byte) (int, error) {
if c.conn == nil {
return 0, ErrChannelNotOpened
@@ -54,7 +60,8 @@ func (c *NetworkChannel) Read(buf []byte) (int, error) {
return c.conn.Read(buf)
}
-// Write
+// Write buffer to a network channel: Returns the number of written bytes and
+// an error code.
func (c *NetworkChannel) Write(buf []byte) (int, error) {
if c.conn == nil {
return 0, ErrChannelNotOpened
@@ -67,8 +74,8 @@ func (c *NetworkChannel) Write(buf []byte) (int, error) {
// NetworkChannelServer
type NetworkChannelServer struct {
- network string
- listener net.Listener
+ network string // network protocol to listen on
+ listener net.Listener // reference to listener object
}
// NewNetworkChannelServer
@@ -79,7 +86,9 @@ func NewNetworkChannelServer(netw string) ChannelServer {
}
}
-// Open
+// Open a network channel server (= start running it) based on the given
+// specification. For every client connection to the server, the associated
+// network channel for the connection is send via the hdlr channel.
func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err
error) {
parts := strings.Split(spec, "+")
// check for correct protocol
@@ -136,7 +145,7 @@ func (s *NetworkChannelServer) Open(spec string, hdlr
chan<- Channel) (err error
return nil
}
-// Close
+// Close a network channel server (= stop the server)
func (s *NetworkChannelServer) Close() error {
if s.listener != nil {
err := s.listener.Close()
@@ -147,27 +156,35 @@ func (s *NetworkChannelServer) Close() error {
}
////////////////////////////////////////////////////////////////////////
+// helper functions to instantiate network channels and servers for
+// common network protocols
+// NewSocketChannel: Unix Domain Socket connection
func NewSocketChannel() Channel {
return NewNetworkChannel("unix")
}
+// NewTCPChannel: TCP connection
func NewTCPChannel() Channel {
return NewNetworkChannel("tcp")
}
+// NewUDPChannel: UDP connection
func NewUDPChannel() Channel {
return NewNetworkChannel("udp")
}
+// NewSocketChannelServer: Unix Domain Socket listener
func NewSocketChannelServer() ChannelServer {
return NewNetworkChannelServer("unix")
}
+// NewTCPChannelServer: TCP listener
func NewTCPChannelServer() ChannelServer {
return NewNetworkChannelServer("tcp")
}
+// NewUDPChannelServer: UDP listener
func NewUDPChannelServer() ChannelServer {
return NewNetworkChannelServer("udp")
}
diff --git a/src/gnunet/transport/connection.go
b/src/gnunet/transport/connection.go
index e66bec1..1cf0317 100644
--- a/src/gnunet/transport/connection.go
+++ b/src/gnunet/transport/connection.go
@@ -5,7 +5,6 @@ import (
"gnunet/message"
)
-////////////////////////////////////////////////////////////////////////
// Connection for communicating peers
type Connection struct {
from, to *core.Peer
@@ -17,6 +16,8 @@ type Connection struct {
shared []byte
}
+// NewConnection instanciates a new connection between peers communicating
+// over a message channel (Connections are authenticated and secured).
func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection {
return &Connection{
from: from,
@@ -26,27 +27,33 @@ func NewConnection(ch *MsgChannel, from, to *core.Peer)
*Connection {
}
}
+// SharedSecret computes the shared secret the two endpoints of a connection.
func (c *Connection) SharedSecret(secret []byte) {
c.shared = make([]byte, len(secret))
copy(c.shared, secret)
}
+// GetState returns the current state of the connection.
func (c *Connection) GetState() int {
return c.state
}
+// SetBandwidth to control transfer rates on the connection
func (c *Connection) SetBandwidth(bw uint32) {
c.bandwidth = bw
}
+// Close connection between two peers.
func (c *Connection) Close() error {
return c.ch.Close()
}
+// Send a message on the connection
func (c *Connection) Send(msg message.Message) error {
return c.ch.Send(msg)
}
+// Receive a message on the connection
func (c *Connection) Receive() (message.Message, error) {
return c.ch.Receive()
}
diff --git a/src/gnunet/transport/session.go b/src/gnunet/transport/session.go
index 90e4016..7d33ea2 100644
--- a/src/gnunet/transport/session.go
+++ b/src/gnunet/transport/session.go
@@ -1,7 +1,6 @@
package transport
-import ()
-
+// Session states
const (
KX_STATE_DOWN = iota // No handshake yet.
KX_STATE_KEY_SENT // We've sent our session key.
diff --git a/src/gnunet/util/address.go b/src/gnunet/util/address.go
index 04e2254..37fb102 100644
--- a/src/gnunet/util/address.go
+++ b/src/gnunet/util/address.go
@@ -1,29 +1,19 @@
package util
import (
+ "encoding/hex"
"fmt"
+ "net"
)
-type IPAddress struct {
- Host []byte `size:"*-2"`
- Port uint16 `order:"big"`
-}
-
-func NewIPAddress(host []byte, port uint16) *IPAddress {
- ip := &IPAddress{
- Host: make([]byte, len(host)),
- Port: port,
- }
- copy(ip.Host, host)
- return ip
-}
-
+// Address specifies how a peer is reachable on the network.
type Address struct {
- Transport string
- Options uint32 `order:"big"`
- Address []byte `size:"*"`
+ Transport string // transport protocol
+ Options uint32 `order:"big"` // address options
+ Address []byte `size:"*"` // address data (protocol-dependent)
}
+// NewAddress returns a new Address for the given transport and specs
func NewAddress(transport string, addr []byte) *Address {
a := &Address{
Transport: transport,
@@ -34,6 +24,37 @@ func NewAddress(transport string, addr []byte) *Address {
return a
}
+// String returns a human-readable representation of an address.
func (a *Address) String() string {
return fmt.Sprintf("Address{%s}", AddressString(a.Transport, a.Address))
}
+
+//----------------------------------------------------------------------
+
+// AddressString returns a string representaion of an address.
+func AddressString(transport string, addr []byte) string {
+ if transport == "tcp" || transport == "udp" {
+ alen := len(addr)
+ port := uint(addr[alen-2])*256 + uint(addr[alen-1])
+ return fmt.Sprintf("%s:%s:%d", transport,
net.IP(addr[:alen-2]).String(), port)
+ }
+ return fmt.Sprintf("%s:%s", transport, hex.EncodeToString(addr))
+}
+
+//----------------------------------------------------------------------
+
+// IP address (can be IPv4 or IPv6 or a DNS name)
+type IPAddress struct {
+ Host []byte `size:"*-2"`
+ Port uint16 `order:"big"`
+}
+
+// NewIPAddress creates a new instance for a given host and port.
+func NewIPAddress(host []byte, port uint16) *IPAddress {
+ ip := &IPAddress{
+ Host: make([]byte, len(host)),
+ Port: port,
+ }
+ copy(ip.Host, host)
+ return ip
+}
diff --git a/src/gnunet/util/array.go b/src/gnunet/util/array.go
index 9076516..f6213bf 100644
--- a/src/gnunet/util/array.go
+++ b/src/gnunet/util/array.go
@@ -30,6 +30,16 @@ func Reverse(b []byte) []byte {
return r
}
+// IsNull returns true if all bytes in an array are set to 0.
+func IsNull(b []byte) bool {
+ for _, v := range b {
+ if v != 0 {
+ return false
+ }
+ }
+ return true
+}
+
// CopyBlock copies 'in' to 'out' so that 'out' is filled completely.
// - If 'in' is larger than 'out', it is left-truncated before copy
// - If 'in' is smaller than 'out', it is left-padded with 0 before copy
diff --git a/src/gnunet/util/format.go b/src/gnunet/util/format.go
index 722b9a7..780c814 100644
--- a/src/gnunet/util/format.go
+++ b/src/gnunet/util/format.go
@@ -1,22 +1,13 @@
package util
import (
- "encoding/hex"
"fmt"
- "net"
)
-func AddressString(transport string, addr []byte) string {
- if transport == "tcp" || transport == "udp" {
- alen := len(addr)
- port := uint(addr[alen-2])*256 + uint(addr[alen-1])
- return fmt.Sprintf("%s:%s:%d", transport,
net.IP(addr[:alen-2]).String(), port)
- }
- return fmt.Sprintf("%s:%s", transport, hex.EncodeToString(addr))
-}
-
var scale = " kMGTPEO"
+// Scale1024 returns an integer value (e.g. a size) as a human-readable
+// string with scales: a size of 183467245 would result in "174,967M"
func Scale1024(n uint64) string {
v := float64(n)
var i int
diff --git a/src/gnunet/util/id.go b/src/gnunet/util/id.go
index 41bd30e..ab9b98c 100644
--- a/src/gnunet/util/id.go
+++ b/src/gnunet/util/id.go
@@ -4,7 +4,8 @@ var (
_id = 0
)
+// generate next unique identifier (unique in the running process/application)
func NextID() int {
- _id += 1
+ _id++
return _id
}
diff --git a/src/gnunet/util/peer_id.go b/src/gnunet/util/peer_id.go
index 03bc73e..6549d75 100644
--- a/src/gnunet/util/peer_id.go
+++ b/src/gnunet/util/peer_id.go
@@ -1,9 +1,11 @@
package util
+// PeerID is the 32-byte binary representation od a Ed25519 key
type PeerID struct {
Key []byte `size:"32"`
}
+// NewPeerID creates a new object from the data.
func NewPeerID(data []byte) *PeerID {
if data == nil {
data = make([]byte, 32)
@@ -22,6 +24,7 @@ func NewPeerID(data []byte) *PeerID {
}
}
+// String returns a human-readable representation of a peer id.
func (p *PeerID) String() string {
return EncodeBinaryToString(p.Key)
}
diff --git a/src/gnunet/util/rnd.go b/src/gnunet/util/rnd.go
index d3c8b2e..a9f247f 100644
--- a/src/gnunet/util/rnd.go
+++ b/src/gnunet/util/rnd.go
@@ -6,16 +6,19 @@ import (
"encoding/binary"
)
+// RndArray fills a buffer with random content
func RndArray(b []byte) {
rand.Read(b)
}
+// NewRndArray creates a new buffer of given size; filled with random content.
func NewRndArray(size int) []byte {
b := make([]byte, size)
rand.Read(b)
return b
}
+// RndUInt64 returns a new 64-bit unsigned random integer.
func RndUInt64() uint64 {
b := make([]byte, 8)
RndArray(b)
@@ -25,22 +28,27 @@ func RndUInt64() uint64 {
return v
}
+// RndInt64 returns a new 64-bit signed random integer.
func RndInt64() int64 {
return int64(RndUInt64())
}
+// RndUInt32 returns a new 32-bit unsigned random integer.
func RndUInt32() uint32 {
return uint32(RndUInt64())
}
+// RndInt32 returns a new 32-bit signed random integer.
func RndInt32() int32 {
return int32(RndUInt64())
}
+// RndUInt16 returns a new 16-bit unsigned random integer.
func RndUInt16() uint16 {
return uint16(RndUInt64())
}
+// RndInt16 returns a new 16-bit signed random integer.
func RndInt16() int16 {
return int16(RndUInt64())
}
--
To stop receiving notification emails like this one, please contact
address@hidden.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnunet-go] branch master updated: MS2-RC1: Recursive resolution and handling of GNS-specific RRs.,
gnunet <=